-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtransform.go
130 lines (111 loc) · 3.58 KB
/
transform.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package toc
import (
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
)
const (
_defaultTitle = "Table of Contents"
// Title depth is [1, 6] inclusive.
_defaultTitleDepth = 1
_maxTitleDepth = 6
)
// Transformer is a Goldmark AST transformer adds a TOC to the top of a
// Markdown document.
//
// To use this, either install the Extender on the goldmark.Markdown object,
// or install the AST transformer on the Markdown parser like so.
//
// markdown := goldmark.New(...)
// markdown.Parser().AddOptions(
// parser.WithAutoHeadingID(),
// parser.WithASTTransformers(
// util.Prioritized(&toc.Transformer{}, 100),
// ),
// )
//
// NOTE: Unless you've supplied your own parser.IDs implementation, you'll
// need to enable the WithAutoHeadingID option on the parser to generate IDs
// and links for headings.
type Transformer struct {
// Title is the title of the table of contents section.
// Defaults to "Table of Contents" if unspecified.
Title string
// TitleDepth is the heading depth for the Title.
// Defaults to 1 (<h1>) if unspecified.
TitleDepth int
// MinDepth is the minimum depth of the table of contents.
// See the documentation for MinDepth for more information.
MinDepth int
// MaxDepth is the maximum depth of the table of contents.
// See the documentation for MaxDepth for more information.
MaxDepth int
// ListID is the id for the list of TOC items rendered in the HTML.
//
// For example, if ListID is "toc", the table of contents will be
// rendered as:
//
// <ul id="toc">
// ...
// </ul>
//
// The HTML element does not have an ID if ListID is empty.
ListID string
// TitleID is the id for the Title heading rendered in the HTML.
//
// For example, if TitleID is "toc-title",
// the title will be rendered as:
//
// <h1 id="toc-title">Table of Contents</h1>
//
// If TitleID is empty, a value will be requested
// from the Goldmark Parser.
TitleID string
// Compact controls whether empty items should be removed
// from the table of contents.
// See the documentation for Compact for more information.
Compact bool
}
var _ parser.ASTTransformer = (*Transformer)(nil) // interface compliance
// Transform adds a table of contents to the provided Markdown document.
//
// Errors encountered while transforming are ignored. For more fine-grained
// control, use Inspect and transform the document manually.
func (t *Transformer) Transform(doc *ast.Document, reader text.Reader, ctx parser.Context) {
toc, err := Inspect(doc, reader.Source(), MinDepth(t.MinDepth), MaxDepth(t.MaxDepth), Compact(t.Compact))
if err != nil {
// There are currently no scenarios under which Inspect
// returns an error but we have to account for it anyway.
return
}
// Don't add anything for documents with no headings.
if len(toc.Items) == 0 {
return
}
listNode := RenderList(toc)
if id := t.ListID; len(id) > 0 {
listNode.SetAttributeString("id", []byte(id))
}
doc.InsertBefore(doc, doc.FirstChild(), listNode)
title := t.Title
if len(title) == 0 {
title = _defaultTitle
}
titleDepth := t.TitleDepth
if titleDepth < 1 {
titleDepth = _defaultTitleDepth
}
if titleDepth > _maxTitleDepth {
titleDepth = _maxTitleDepth
}
titleBytes := []byte(title)
heading := ast.NewHeading(titleDepth)
heading.AppendChild(heading, ast.NewString(titleBytes))
if id := t.TitleID; len(id) > 0 {
heading.SetAttributeString("id", []byte(id))
} else if ids := ctx.IDs(); ids != nil {
id := ids.Generate(titleBytes, heading.Kind())
heading.SetAttributeString("id", id)
}
doc.InsertBefore(doc, doc.FirstChild(), heading)
}