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

mlange-42 / modo / 12877300192

20 Jan 2025 11:41PM CUT coverage: 60.111%. Remained the same
12877300192

push

github

web-flow
Extend the user guide (#84)

972 of 1617 relevant lines covered (60.11%)

28.0 hits per line

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

78.92
/document/links.go
1
package document
2

3
import (
4
        "fmt"
5
        "path"
6
        "regexp"
7
        "strings"
8
)
9

10
const regexString = `(?s)(?:(` + "```.*?```)|(`.*?`" + `))|(\[.*?\])`
11

12
func (proc *Processor) processLinks(docs *Docs) error {
6✔
13
        return proc.walkDocs(docs, proc.replaceRefs, func(elem Named) string {
51✔
14
                return elem.GetName()
45✔
15
        })
45✔
16
}
17

18
func (proc *Processor) replaceRefs(text string, elems []string, modElems int) (string, error) {
295✔
19
        indices, err := findLinks(text)
295✔
20
        if err != nil {
295✔
21
                return "", err
×
22
        }
×
23
        if len(indices) == 0 {
528✔
24
                return text, nil
233✔
25
        }
233✔
26
        for i := len(indices) - 2; i >= 0; i -= 2 {
182✔
27
                start, end := indices[i], indices[i+1]
120✔
28
                link := text[start+1 : end-1]
120✔
29

120✔
30
                content, ok, err := proc.refToPlaceholder(link, elems, modElems)
120✔
31
                if err != nil {
120✔
32
                        return "", err
×
33
                }
×
34
                if !ok {
120✔
35
                        continue
×
36
                }
37
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
120✔
38
        }
39
        return text, nil
62✔
40
}
41

42
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
34✔
43
        indices, err := findLinks(text)
34✔
44
        if err != nil {
34✔
45
                return "", err
×
46
        }
×
47
        if len(indices) == 0 {
54✔
48
                return text, nil
20✔
49
        }
20✔
50
        for i := len(indices) - 2; i >= 0; i -= 2 {
126✔
51
                start, end := indices[i], indices[i+1]
112✔
52
                link := text[start+1 : end-1]
112✔
53

112✔
54
                entry, linkText, parts, ok, err := proc.placeholderToLink(link, elems, modElems, proc.Config.ShortLinks)
112✔
55
                if err != nil {
112✔
56
                        return "", err
×
57
                }
×
58
                if !ok {
112✔
59
                        continue
×
60
                }
61

62
                var basePath string
112✔
63
                if entry.IsSection {
190✔
64
                        basePath = path.Join(parts[:len(parts)-1]...)
78✔
65
                } else {
112✔
66
                        basePath = path.Join(parts...)
34✔
67
                }
34✔
68

69
                pathStr, err := proc.Formatter.ToLinkPath(basePath, entry.Kind)
112✔
70
                if err != nil {
112✔
71
                        return "", err
×
72
                }
×
73
                if entry.IsSection {
190✔
74
                        pathStr += parts[len(parts)-1]
78✔
75
                }
78✔
76
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
112✔
77
        }
78
        return text, nil
14✔
79
}
80

81
func (proc *Processor) placeholderToLink(link string, elems []string, modElems int, shorten bool) (entry *elemPath, text string, parts []string, ok bool, err error) {
112✔
82
        linkParts := strings.SplitN(link, " ", 2)
112✔
83
        entry, text, parts, ok, err = proc.placeholderToRelLink(linkParts[0], elems, modElems)
112✔
84
        if err != nil {
112✔
85
                return
×
86
        }
×
87
        if !ok {
112✔
88
                return
×
89
        }
×
90
        if len(linkParts) > 1 {
113✔
91
                text = linkParts[1]
1✔
92
        } else {
112✔
93
                if shorten {
222✔
94
                        textParts := strings.Split(text, ".")
111✔
95
                        if entry.IsSection {
188✔
96
                                text = strings.Join(textParts[len(textParts)-2:], ".")
77✔
97
                        } else {
111✔
98
                                text = textParts[len(textParts)-1]
34✔
99
                        }
34✔
100
                }
101
                text = fmt.Sprintf("`%s`", text)
111✔
102
        }
103
        return
112✔
104
}
105

106
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool, error) {
112✔
107
        elemPath, ok := proc.linkTargets[link]
112✔
108
        if !ok {
112✔
109
                err := proc.warnOrError("Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
110
                return nil, "", nil, false, err
×
111
        }
×
112
        skip := 0
112✔
113
        for range modElems {
254✔
114
                if skip >= len(elemPath.Elements) {
143✔
115
                        break
1✔
116
                }
117
                if elemPath.Elements[skip] == elems[skip] {
280✔
118
                        skip++
139✔
119
                } else {
141✔
120
                        break
2✔
121
                }
122
        }
123
        fullPath := []string{}
112✔
124
        for range modElems - skip {
115✔
125
                fullPath = append(fullPath, "..")
3✔
126
        }
3✔
127
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
112✔
128
        if len(fullPath) == 0 {
114✔
129
                fullPath = []string{"."}
2✔
130
        }
2✔
131
        return &elemPath, link, fullPath, true, nil
112✔
132
}
133

134
func (proc *Processor) refToPlaceholder(link string, elems []string, modElems int) (string, bool, error) {
120✔
135
        linkParts := strings.SplitN(link, " ", 2)
120✔
136

120✔
137
        var placeholder string
120✔
138
        var ok bool
120✔
139
        var err error
120✔
140
        if strings.HasPrefix(link, ".") {
218✔
141
                placeholder, ok, err = proc.refToPlaceholderRel(linkParts[0], elems, modElems)
98✔
142
        } else {
120✔
143
                placeholder, ok, err = proc.refToPlaceholderAbs(linkParts[0], elems)
22✔
144
        }
22✔
145
        if err != nil {
120✔
146
                return "", false, err
×
147
        }
×
148
        if !ok {
120✔
149
                return "", false, nil
×
150
        }
×
151

152
        if len(linkParts) > 1 {
121✔
153
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true, nil
1✔
154
        } else {
120✔
155
                return placeholder, true, nil
119✔
156
        }
119✔
157
}
158

159
func (proc *Processor) refToPlaceholderRel(link string, elems []string, modElems int) (string, bool, error) {
98✔
160
        dots := 0
98✔
161
        for strings.HasPrefix(link[dots:], ".") {
201✔
162
                dots++
103✔
163
        }
103✔
164
        if dots > modElems {
98✔
165
                err := proc.warnOrError("Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
166
                return "", false, err
×
167
        }
×
168
        linkText := link[dots:]
98✔
169
        subElems := elems[:modElems-(dots-1)]
98✔
170
        var fullLink string
98✔
171
        if len(subElems) == 0 {
98✔
172
                fullLink = linkText
×
173
        } else {
98✔
174
                fullLink = strings.Join(subElems, ".") + "." + linkText
98✔
175
        }
98✔
176

177
        placeholder, ok := proc.linkExports[fullLink]
98✔
178
        if !ok {
98✔
179
                err := proc.warnOrError("Can't resolve cross ref (rel) '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
×
180
                return "", false, err
×
181
        }
×
182
        return placeholder, true, nil
98✔
183
}
184

185
func (proc *Processor) refToPlaceholderAbs(link string, elems []string) (string, bool, error) {
22✔
186
        placeholder, ok := proc.linkExports[link]
22✔
187
        if !ok {
22✔
188
                err := proc.warnOrError("Can't resolve cross ref (abs) '%s' in %s", link, strings.Join(elems, "."))
×
189
                return "", false, err
×
190
        }
×
191
        return placeholder, true, nil
22✔
192
}
193

194
func findLinks(text string) ([]int, error) {
330✔
195
        re, err := regexp.Compile(regexString)
330✔
196
        if err != nil {
330✔
197
                return nil, err
×
198
        }
×
199
        links := []int{}
330✔
200
        results := re.FindAllStringSubmatchIndex(text, -1)
330✔
201
        for _, r := range results {
743✔
202
                if r[6] >= 0 {
676✔
203
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
292✔
204
                                continue
29✔
205
                        }
206
                        links = append(links, r[6], r[7])
234✔
207
                }
208
        }
209

210
        return links, nil
330✔
211
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc