Skip to content

Commit

Permalink
markdown: allow any character to be used as heading IDs (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
unknwon authored Apr 25, 2022
1 parent 98d9615 commit 7940737
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
48 changes: 47 additions & 1 deletion internal/store/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package store

import (
"bytes"
"fmt"
"net/url"
"os"
"path"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/yuin/goldmark/parser"
goldmarkhtml "github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)

func convertFile(pathPrefix, file string) (content []byte, meta map[string]any, headings goldmarktoc.Items, err error) {
Expand Down Expand Up @@ -50,7 +52,11 @@ func convertFile(pathPrefix, file string) (content []byte, meta map[string]any,
),
)

ctx := parser.NewContext()
ctx := parser.NewContext(
func(cfg *parser.ContextConfig) {
cfg.IDs = newIDs()
},
)
doc := md.Parser().Parse(text.NewReader(body), parser.WithContext(ctx))

// Headings
Expand Down Expand Up @@ -135,3 +141,43 @@ func inspectLinks(pathPrefix string, doc ast.Node) error {
return ast.WalkSkipChildren, nil
})
}

// ids is a modified version to allow any non-whitespace characters instead of
// just alphabets or numerics from
// https://github.com/yuin/goldmark/blob/113ae87dd9e662b54012a596671cb38f311a8e9c/parser/parser.go#L65.
type ids struct {
values map[string]bool
}

func newIDs() parser.IDs {
return &ids{
values: map[string]bool{},
}
}

func (s *ids) Generate(value []byte, kind ast.NodeKind) []byte {
value = util.TrimLeftSpace(value)
value = util.TrimRightSpace(value)
if len(value) == 0 {
if kind == ast.KindHeading {
value = []byte("heading")
} else {
value = []byte("id")
}
}
if _, ok := s.values[util.BytesToReadOnlyString(value)]; !ok {
s.values[util.BytesToReadOnlyString(value)] = true
return value
}
for i := 1; ; i++ {
newResult := fmt.Sprintf("%s-%d", value, i)
if _, ok := s.values[newResult]; !ok {
s.values[newResult] = true
return []byte(newResult)
}
}
}

func (s *ids) Put(value []byte) {
s.values[util.BytesToReadOnlyString(value)] = true
}
55 changes: 55 additions & 0 deletions internal/store/markdown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2022 ASoulDocs. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package store

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/yuin/goldmark/ast"
)

func TestIDs_Generate(t *testing.T) {
ids := newIDs()

tests := []struct {
name string
value string
kind ast.NodeKind
want string
}{
{
name: "normal",
value: "Hello, 世界",
kind: ast.KindHeading,
want: "Hello, 世界",
},
{
name: "empty heading",
value: "",
kind: ast.KindHeading,
want: "heading",
},
{
name: "empty id",
value: "",
kind: ast.KindImage,
want: "id",
},

{
name: "duplicated heading",
value: "",
kind: ast.KindHeading,
want: "heading-1",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := ids.Generate([]byte(test.value), test.kind)
assert.Equal(t, test.want, string(got))
})
}
}

0 comments on commit 7940737

Please sign in to comment.