Feat: Use custom heading anchors

Confluence Anchors are case-sensitive.
This commit is contained in:
Manuel Rüger 2024-10-22 10:50:06 +02:00
parent e7a3877ded
commit 876626098b
8 changed files with 98 additions and 36 deletions

View File

@ -91,8 +91,10 @@ func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidPr
html.WithXHTML(),
))
ctx := parser.NewContext(parser.WithIDs(&cparser.ConfluenceIDs{Values: map[string]bool{}}))
var buf bytes.Buffer
err := converter.Convert(markdown, &buf)
err := converter.Convert(markdown, &buf, parser.WithContext(ctx))
if err != nil {
panic(err)

56
parser/confluenceids.go Normal file
View File

@ -0,0 +1,56 @@
package parser
import (
"fmt"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/util"
)
type ConfluenceIDs struct {
Values map[string]bool
}
// https://github.com/yuin/goldmark/blob/d9c03f07f08c2d36f23afe52dda865f05320ac86/parser/parser.go#L75
func (s *ConfluenceIDs) Generate(value []byte, kind ast.NodeKind) []byte {
value = util.TrimLeftSpace(value)
value = util.TrimRightSpace(value)
result := []byte{}
for i := 0; i < len(value); {
v := value[i]
l := util.UTF8Len(v)
i += int(l)
if l != 1 {
continue
}
if util.IsAlphaNumeric(v) || v == '/' || v == '_' || v == '.' {
result = append(result, v)
} else if util.IsSpace(v) || v == '-' {
result = append(result, '-')
}
}
if len(result) == 0 {
if kind == ast.KindHeading {
result = []byte("heading")
} else {
result = []byte("id")
}
}
if _, ok := s.Values[util.BytesToReadOnlyString(result)]; !ok {
s.Values[util.BytesToReadOnlyString(result)] = true
return result
}
for i := 1; ; i++ {
newResult := fmt.Sprintf("%s-%d", result, i)
if _, ok := s.Values[newResult]; !ok {
s.Values[newResult] = true
return []byte(newResult)
}
}
}
func (s *ConfluenceIDs) Put(value []byte) {
s.Values[util.BytesToReadOnlyString(value)] = true
}

View File

@ -4,3 +4,4 @@
<h5 id="e">e</h5>
<h1 id="f">f</h1>
<h2 id="g">g</h2>
<h1 id="This/is-some_Heading.yml">This/is some_Heading.yml</h1>

View File

@ -5,3 +5,4 @@
<h5 id="e">e</h5>
<h1 id="f">f</h1>
<h2 id="g">g</h2>
<h1 id="This/is-some_Heading.yml">This/is some_Heading.yml</h1>

2
testdata/header.md vendored
View File

@ -8,3 +8,5 @@ f
=
g
-
# This/is some_Heading.yml

View File

@ -1,4 +1,4 @@
<h2 id="first-heading">First Heading</h2>
<h2 id="First-Heading">First Heading</h2>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>NOTES:</strong></p>
<ol>
@ -11,7 +11,7 @@ b</p>
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="second-heading">Second Heading</h2>
<h2 id="Second-Heading">Second Heading</h2>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>Warn</strong></p>
<ul>
@ -23,12 +23,12 @@ b</p>
<li>Regular list
that runs long</li>
</ul>
<h2 id="third-heading">Third Heading</h2>
<h2 id="Third-Heading">Third Heading</h2>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<!-- Info -->
<p>Test</p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="fourth-heading---warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<h2 id="Fourth-Heading---Warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>TIP:</strong></p>
<ol>
@ -41,12 +41,12 @@ b</p>
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="simple-blockquote">Simple Blockquote</h2>
<h2 id="Simple-Blockquote">Simple Blockquote</h2>
<blockquote>
<p>This paragraph is a simple blockquote</p>
</blockquote>
<h2 id="gh-alerts-heading">GH Alerts Heading</h2>
<h3 id="note-type-alert-heading">Note Type Alert Heading</h3>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<ul>
@ -54,7 +54,7 @@ b</p>
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="tip-type-alert-heading">Tip Type Alert Heading</h3>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<ul>
@ -62,7 +62,7 @@ b</p>
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="warning-type-alert-heading">Warning Type Alert Heading</h3>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<ul>
@ -70,7 +70,7 @@ b</p>
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="importantcaution-type-alert-heading">Important/Caution Type Alert Heading</h3>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<ul>
@ -85,7 +85,7 @@ b</p>
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<h3 id="Should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<blockquote>
<p>[[!NOTE]</p>
</blockquote>

View File

@ -1,5 +1,5 @@
<h1 id="main-heading">Main Heading</h1>
<h2 id="first-heading">First Heading</h2>
<h1 id="Main-Heading">Main Heading</h1>
<h2 id="First-Heading">First Heading</h2>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>NOTES:</strong></p>
<ol>
@ -11,7 +11,7 @@
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="second-heading">Second Heading</h2>
<h2 id="Second-Heading">Second Heading</h2>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>Warn</strong></p>
<ul>
@ -22,12 +22,12 @@
<ul>
<li>Regular list that runs long</li>
</ul>
<h2 id="third-heading">Third Heading</h2>
<h2 id="Third-Heading">Third Heading</h2>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<!-- Info -->
<p>Test</p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="fourth-heading---warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<h2 id="Fourth-Heading---Warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>TIP:</strong></p>
<ol>
@ -39,12 +39,12 @@
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="simple-blockquote">Simple Blockquote</h2>
<h2 id="Simple-Blockquote">Simple Blockquote</h2>
<blockquote>
<p>This paragraph is a simple blockquote</p>
</blockquote>
<h2 id="gh-alerts-heading">GH Alerts Heading</h2>
<h3 id="note-type-alert-heading">Note Type Alert Heading</h3>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<ul>
@ -52,7 +52,7 @@
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="tip-type-alert-heading">Tip Type Alert Heading</h3>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<ul>
@ -60,7 +60,7 @@
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="warning-type-alert-heading">Warning Type Alert Heading</h3>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<ul>
@ -68,7 +68,7 @@
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="importantcaution-type-alert-heading">Important/Caution Type Alert Heading</h3>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<ul>
@ -83,7 +83,7 @@
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<h3 id="Should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<blockquote>
<p>[[!NOTE]</p>
</blockquote>

24
testdata/quotes.html vendored
View File

@ -1,5 +1,5 @@
<h1 id="main-heading">Main Heading</h1>
<h2 id="first-heading">First Heading</h2>
<h1 id="Main-Heading">Main Heading</h1>
<h2 id="First-Heading">First Heading</h2>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>NOTES:</strong></p>
<ol>
@ -12,7 +12,7 @@ b</p>
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="second-heading">Second Heading</h2>
<h2 id="Second-Heading">Second Heading</h2>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>Warn</strong></p>
<ul>
@ -24,12 +24,12 @@ b</p>
<li>Regular list
that runs long</li>
</ul>
<h2 id="third-heading">Third Heading</h2>
<h2 id="Third-Heading">Third Heading</h2>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<!-- Info -->
<p>Test</p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="fourth-heading---warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<h2 id="Fourth-Heading---Warn-should-not-get-picked-as-block-quote">Fourth Heading - Warn should not get picked as block quote</h2>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p><strong>TIP:</strong></p>
<ol>
@ -42,12 +42,12 @@ b</p>
</blockquote>
<p><strong>Warn (Should not be picked as blockquote type)</strong></p>
</ac:rich-text-body></ac:structured-macro>
<h2 id="simple-blockquote">Simple Blockquote</h2>
<h2 id="Simple-Blockquote">Simple Blockquote</h2>
<blockquote>
<p>This paragraph is a simple blockquote</p>
</blockquote>
<h2 id="gh-alerts-heading">GH Alerts Heading</h2>
<h3 id="note-type-alert-heading">Note Type Alert Heading</h3>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<ul>
@ -55,7 +55,7 @@ b</p>
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="tip-type-alert-heading">Tip Type Alert Heading</h3>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<ul>
@ -63,7 +63,7 @@ b</p>
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="warning-type-alert-heading">Warning Type Alert Heading</h3>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<ul>
@ -71,7 +71,7 @@ b</p>
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="importantcaution-type-alert-heading">Important/Caution Type Alert Heading</h3>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<ul>
@ -86,7 +86,7 @@ b</p>
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<h3 id="Should-not-be-picked-up-and-converted-into-blockquote-macro">Should not be picked up and converted into blockquote macro</h3>
<blockquote>
<p>[[!NOTE]</p>
</blockquote>