-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.go
More file actions
123 lines (104 loc) · 2.32 KB
/
parser.go
File metadata and controls
123 lines (104 loc) · 2.32 KB
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
package termwind
import (
"strings"
"golang.org/x/net/html"
)
var supportedTags = map[Tag]bool{
TagAnchor: true,
TagBreakLine: true,
TagDd: true,
TagDiv: true,
TagDl: true,
TagDt: true,
TagHr: true,
TagLi: true,
TagOl: true,
TagParagraph: true,
TagRaw: true,
TagSpan: true,
TagUl: true,
}
func Parse(input string) (*Element, error) {
input = strings.TrimSpace(input)
if !strings.HasPrefix(input, "<") {
input = "<div>" + input + "</div>"
}
doc, err := html.Parse(strings.NewReader(input))
if err != nil {
return nil, err
}
root := findContent(doc)
if root == nil {
return &Element{Tag: TagDiv}, nil
}
return root, nil
}
func findContent(node *html.Node) *Element {
if node.Type == html.ElementNode {
tag := Tag(node.Data)
if supportedTags[tag] {
return walkNode(node, nil)
}
}
for child := node.FirstChild; child != nil; child = child.NextSibling {
if el := findContent(child); el != nil {
return el
}
}
return nil
}
func walkNode(node *html.Node, parent *Element) *Element {
if node.Type == html.TextNode {
if parent == nil {
return nil
}
text := node.Data
if !parent.Tag.IsInline() {
text = strings.TrimSpace(node.Data)
}
if text == "" {
return nil
}
textEl := &Element{Tag: TagRaw, Content: text, Parent: parent}
parent.Children = append(parent.Children, textEl)
return nil
}
if node.Type != html.ElementNode {
walkChildren(node, parent)
return nil
}
tag := Tag(node.Data)
if !supportedTags[tag] {
walkChildren(node, parent)
return nil
}
el := &Element{
Tag: tag,
Parent: parent,
}
for _, attr := range node.Attr {
if attr.Key == "class" {
el.Classes = strings.Fields(attr.Val)
} else {
if el.Attrs == nil {
el.Attrs = make(map[string]string)
}
el.Attrs[attr.Key] = attr.Val
}
}
if len(el.Classes) > 0 {
el.Style = ParseClasses(el.Classes)
}
walkChildren(node, el)
return el
}
// walkChildren recurses through all siblings of a node's children,
// appending any resulting elements to the parent's Children slice.
func walkChildren(node *html.Node, parent *Element) {
for c := node.FirstChild; c != nil; c = c.NextSibling {
child := walkNode(c, parent)
if child != nil && parent != nil {
parent.Children = append(parent.Children, child)
}
}
}