-
Notifications
You must be signed in to change notification settings - Fork 1
/
links.go
73 lines (57 loc) · 1.37 KB
/
links.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
package crawler
import "strings"
// Link represents a link to a resource.
type Link map[string]string
// Links is a slice of links.
type Links []Link
type LinkMatcher func(link Link) bool
type linkCandidate struct {
link Link
priority int
order int
}
func LinkTypeApplicationJSON(link Link) bool {
return strings.ToLower(link["type"]) == "application/json"
}
func LinkTypeAnyJSON(link Link) bool {
return strings.HasSuffix(strings.ToLower(link["type"]), "json")
}
func LinkTypeGeoJSON(link Link) bool {
return strings.ToLower(link["type"]) == "application/geo+json"
}
func LinkTypeNone(link Link) bool {
_, hasType := link["type"]
return !hasType
}
func (links Links) Rel(rel string, matchers ...LinkMatcher) Link {
candidates := []*linkCandidate{}
for order, link := range links {
if link["rel"] == rel {
if len(matchers) == 0 {
return link
}
for priority, matcher := range matchers {
if matcher(link) {
candidates = append(candidates, &linkCandidate{link: link, priority: priority, order: order})
}
}
}
}
if len(candidates) == 0 {
return nil
}
best := candidates[0]
for _, candidate := range candidates {
if candidate.priority > best.priority {
continue
}
if candidate.priority < best.priority {
best = candidate
continue
}
if candidate.order < best.order {
best = candidate
}
}
return best.link
}