• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yuin / goldmark / 29184789560

12 Jul 2026 07:46AM UTC coverage: 82.991% (-1.2%) from 84.201%
29184789560

push

github

yuin
perf: Optimize text/value WriteTo methods to avoid unnecessary allocations and copying

39 of 75 new or added lines in 2 files covered. (52.0%)

368 existing lines in 14 files now uncovered.

6392 of 7702 relevant lines covered (82.99%)

349203.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.13
/parser/attribute.go
1
package parser
2

3
import (
4
        "bytes"
5

6
        gast "github.com/yuin/goldmark/v2/ast"
7
        "github.com/yuin/goldmark/v2/text"
8
        "github.com/yuin/goldmark/v2/util"
9
)
10

11
// ParseAttributes parses attributes into a slice of ast.Attribute.
12
// ParseAttributes returns a parsed attributes and true if could parse
13
// attributes, otherwise nil and false.
14
func ParseAttributes(reader text.Reader) ([]gast.Attribute, bool) {
42✔
15
        savedLine, savedPosition := reader.Position()
42✔
16
        reader.SkipSpaces()
42✔
17
        if reader.Peek() != '{' {
42✔
UNCOV
18
                reader.SetPosition(savedLine, savedPosition)
×
UNCOV
19
                return nil, false
×
UNCOV
20
        }
×
21
        reader.Advance(1)
42✔
22
        var attrs []gast.Attribute
42✔
23
        for {
174✔
24
                if reader.Peek() == '}' {
171✔
25
                        reader.Advance(1)
39✔
26
                        return attrs, true
39✔
27
                }
39✔
28
                attr, ok := parseAttribute(reader)
93✔
29
                if !ok {
96✔
30
                        reader.SetPosition(savedLine, savedPosition)
3✔
31
                        return nil, false
3✔
32
                }
3✔
33
                if attr.Name == "class" {
129✔
34
                        updated := false
39✔
35
                        for i, a := range attrs {
93✔
36
                                if a.Name == "class" {
69✔
37
                                        existing := a.Value.Str(nil)
15✔
38
                                        newVal := attr.Value.Str(nil)
15✔
39
                                        attrs[i].Value = text.NewStringMultilineValue(existing + " " + newVal)
15✔
40
                                        updated = true
15✔
41
                                        break
15✔
42
                                }
43
                        }
44
                        if !updated {
63✔
45
                                attrs = append(attrs, attr)
24✔
46
                        }
24✔
47
                } else {
51✔
48
                        attrs = append(attrs, attr)
51✔
49
                }
51✔
50
                reader.SkipSpaces()
90✔
51
                if reader.Peek() == ',' {
102✔
52
                        reader.Advance(1)
12✔
53
                        reader.SkipSpaces()
12✔
54
                }
12✔
55
        }
56
}
57

58
func parseAttribute(reader text.Reader) (gast.Attribute, bool) {
93✔
59
        reader.SkipSpaces()
93✔
60
        c := reader.Peek()
93✔
61
        if c == '#' || c == '.' {
150✔
62
                reader.Advance(1)
57✔
63
                line, _ := reader.PeekLine()
57✔
64
                i := 0
57✔
65
                for i < len(line) && (!util.IsSpace(line[i]) &&
57✔
66
                        (!util.IsPunct(line[i]) || line[i] == '_' ||
57✔
67
                                line[i] == '-' || line[i] == ':' || line[i] == '.')) {
375✔
68
                        i++
318✔
69
                }
318✔
70
                name := "class"
57✔
71
                if c == '#' {
90✔
72
                        name = "id"
33✔
73
                }
33✔
74
                reader.Advance(i)
57✔
75
                return gast.Attribute{
57✔
76
                        Name:  name,
57✔
77
                        Value: text.NewStringMultilineValue(string(line[0:i])),
57✔
78
                }, true
57✔
79
        }
80
        line, _ := reader.PeekLine()
36✔
81
        if len(line) == 0 {
36✔
UNCOV
82
                return gast.Attribute{}, false
×
UNCOV
83
        }
×
84
        c = line[0]
36✔
85
        if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&
36✔
86
                c != '_' && c != ':' {
36✔
UNCOV
87
                return gast.Attribute{}, false
×
UNCOV
88
        }
×
89
        i := 0
36✔
90
        for ; i < len(line); i++ {
339✔
91
                c = line[i]
303✔
92
                if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&
303✔
93
                        (c < '0' || c > '9') &&
303✔
94
                        c != '_' && c != ':' && c != '.' && c != '-' {
339✔
95
                        break
36✔
96
                }
97
        }
98
        name := line[:i]
36✔
99
        reader.Advance(i)
36✔
100
        reader.SkipSpaces()
36✔
101
        c = reader.Peek()
36✔
102
        if c != '=' {
36✔
UNCOV
103
                return gast.Attribute{}, false
×
UNCOV
104
        }
×
105
        reader.Advance(1)
36✔
106
        reader.SkipSpaces()
36✔
107
        value, ok := parseAttributeValue(reader)
36✔
108
        if !ok {
39✔
109
                return gast.Attribute{}, false
3✔
110
        }
3✔
111
        return gast.Attribute{
33✔
112
                Name:  util.BytesToReadOnlyString(name),
33✔
113
                Value: value,
33✔
114
        }, true
33✔
115
}
116

117
func parseAttributeValue(reader text.Reader) (text.MultilineValue, bool) {
36✔
118
        reader.SkipSpaces()
36✔
119
        c := reader.Peek()
36✔
120
        switch c {
36✔
UNCOV
121
        case text.EOF:
×
UNCOV
122
                return text.MultilineValue{}, false
×
123
        case '"':
9✔
124
                return parseAttributeString(reader)
9✔
125
        default:
27✔
126
                return parseAttributeWord(reader)
27✔
127
        }
128
}
129

130
func parseAttributeString(reader text.Reader) (text.MultilineValue, bool) {
9✔
131
        reader.Advance(1) // skip "
9✔
132
        line, _ := reader.PeekLine()
9✔
133
        i := 0
9✔
134
        l := len(line)
9✔
135
        var buf bytes.Buffer
9✔
136
        for i < l {
96✔
137
                c := line[i]
87✔
138
                if c == '\\' && i != l-1 {
90✔
139
                        n := line[i+1]
3✔
140
                        switch n {
3✔
141
                        case '"', '/', '\\':
3✔
142
                                buf.WriteByte(n)
3✔
143
                                i += 2
3✔
UNCOV
144
                        case 'b':
×
UNCOV
145
                                buf.WriteString("\b")
×
UNCOV
146
                                i += 2
×
147
                        case 'f':
×
148
                                buf.WriteString("\f")
×
149
                                i += 2
×
150
                        case 'n':
×
151
                                buf.WriteString("\n")
×
152
                                i += 2
×
153
                        case 'r':
×
154
                                buf.WriteString("\r")
×
155
                                i += 2
×
156
                        case 't':
×
157
                                buf.WriteString("\t")
×
158
                                i += 2
×
159
                        default:
×
160
                                buf.WriteByte('\\')
×
161
                                i++
×
162
                        }
163
                        continue
3✔
164
                }
165
                if c == '"' {
93✔
166
                        reader.Advance(i + 1)
9✔
167
                        return text.NewStringMultilineValue(buf.String()), true
9✔
168
                }
9✔
169
                buf.WriteByte(c)
75✔
170
                i++
75✔
171
        }
UNCOV
172
        return text.MultilineValue{}, false
×
173
}
174

175
func parseAttributeWord(reader text.Reader) (text.MultilineValue, bool) {
27✔
176
        line, _ := reader.PeekLine()
27✔
177
        c := line[0]
27✔
178
        if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&
27✔
179
                c != '_' && c != ':' {
30✔
180
                return text.MultilineValue{}, false
3✔
181
        }
3✔
182
        i := 0
24✔
183
        for ; i < len(line); i++ {
183✔
184
                c := line[i]
159✔
185
                if (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&
159✔
186
                        (c < '0' || c > '9') &&
159✔
187
                        c != '_' && c != ':' && c != '.' && c != '-' {
183✔
188
                        break
24✔
189
                }
190
        }
191
        reader.Advance(i)
24✔
192
        return text.NewStringMultilineValue(string(line[:i])), true
24✔
193
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc