forked from mmarkdown/mmark
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodes.go
171 lines (152 loc) · 3.51 KB
/
nodes.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package mast
import (
"bytes"
"sort"
"github.com/gomarkdown/markdown/ast"
)
// some extra functions for manipulation the AST
// MoveChilderen moves the children from a to b *and* make the parent of each point to b.
// Any children of b are obliterated.
func MoveChildren(a, b ast.Node) {
a.SetChildren(b.GetChildren())
b.SetChildren(nil)
for _, child := range a.GetChildren() {
child.SetParent(a)
}
}
// Some attribute helper functions.
// AttributeFromNode returns the attribute from the node, if it was there was one.
func AttributeFromNode(node ast.Node) *ast.Attribute {
if c := node.AsContainer(); c != nil && c.Attribute != nil {
return c.Attribute
}
if l := node.AsLeaf(); l != nil && l.Attribute != nil {
return l.Attribute
}
return nil
}
// AttributeInit will initialize an *Attribute on node if there wasn't one.
func AttributeInit(node ast.Node) {
if l := node.AsLeaf(); l != nil && l.Attribute == nil {
l.Attribute = &ast.Attribute{Attrs: make(map[string][]byte)}
return
}
if c := node.AsContainer(); c != nil && c.Attribute == nil {
c.Attribute = &ast.Attribute{Attrs: make(map[string][]byte)}
return
}
}
// DeleteAttribute delete the attribute under key from a.
func DeleteAttribute(node ast.Node, key string) {
a := AttributeFromNode(node)
if a == nil {
return
}
switch key {
case "id":
a.ID = nil
case "class":
// TODO
default:
delete(a.Attrs, key)
}
}
// SetAttribute sets the attribute under key to value.
func SetAttribute(node ast.Node, key string, value []byte) {
a := AttributeFromNode(node)
if a == nil {
return
}
switch key {
case "id":
a.ID = value
case "class":
// TODO
default:
a.Attrs[key] = value
}
}
// Attribute returns the attribute value under key. Use AttributeClass to retrieve
// a class.
func Attribute(node ast.Node, key string) []byte {
a := AttributeFromNode(node)
if a == nil {
return nil
}
switch key {
case "id":
return a.ID
case "class":
// use AttributeClass.
}
return a.Attrs[key]
}
func AttributeBytes(attr *ast.Attribute) []byte {
ret := &bytes.Buffer{}
ret.WriteByte('{')
if len(attr.ID) != 0 {
ret.WriteByte('#')
ret.Write(attr.ID)
}
for _, c := range attr.Classes {
if ret.Len() > 1 {
ret.WriteByte(' ')
}
ret.WriteByte('.')
ret.Write(c)
}
keys := []string{}
for k := range attr.Attrs {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if ret.Len() > 1 {
ret.WriteByte(' ')
}
ret.WriteString(k)
ret.WriteString(`="`)
ret.Write(attr.Attrs[k])
ret.WriteByte('"')
}
ret.WriteByte('}')
return ret.Bytes()
}
// AttributeClass returns true is class key is set.
func AttributeClass(node ast.Node, key string) bool {
a := AttributeFromNode(node)
if a == nil {
return false
}
for _, c := range a.Classes {
if string(c) == key {
return true
}
}
return false
}
// AttributeFilter runs the attribute on node through filter and only allows elements for which filter returns true.
func AttributeFilter(node ast.Node, filter func(key string) bool) {
a := AttributeFromNode(node)
if a == nil {
return
}
if !filter("id") {
a.ID = nil
}
if !filter("class") {
a.Classes = nil
}
for k := range a.Attrs {
if !filter(k) {
delete(a.Attrs, k)
}
}
}
// FilterFunc checks if s is an allowed key in an attribute.
// If s is:
// "id" the ID should be checked
// "class" the classes should be allowed or disallowed
// any other string means checking the individual attributes.
// it returns true for elements that are allows, false otherwise.
type FilterFunc func(s string) bool