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

mlange-42 / modo / 13167566672

05 Feb 2025 10:14PM CUT coverage: 72.072% (-0.6%) from 72.707%
13167566672

Pull #208

github

web-flow
Merge 3d1ae8088 into c98120bba
Pull Request #208: Inheritance for method docs from parent trait

142 of 194 new or added lines in 4 files covered. (73.2%)

25 existing lines in 1 file now uncovered.

1729 of 2399 relevant lines covered (72.07%)

26.86 hits per line

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

83.01
/internal/document/links.go
1
package document
2

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

10
const linkRegexString = `(?s)(?:(` + "```.*?```)|(`.*?`" + `))|(\[.*?\])`
11
const transcludeRegexString = `(?s)(?:(` + "```.*?```)|(`.*?`" + `))|(\{.*?\})`
12

13
var linkRegex *regexp.Regexp
14
var transcludeRegex *regexp.Regexp
15

16
func init() {
2✔
17
        var err error
2✔
18
        linkRegex, err = regexp.Compile(linkRegexString)
2✔
19
        if err != nil {
2✔
NEW
20
                panic(err)
×
21
        }
22
        transcludeRegex, err = regexp.Compile(transcludeRegexString)
2✔
23
        if err != nil {
2✔
24
                panic(err)
×
25
        }
26
}
27

28
func (proc *Processor) processLinks(docs *Docs) error {
6✔
29
        return proc.walkAllDocStrings(docs, proc.replaceRefs, func(elem Named) string {
53✔
30
                return elem.GetName()
47✔
31
        })
47✔
32
}
33

34
func (proc *Processor) replaceRefs(text string, elems []string, modElems int) (string, error) {
355✔
35
        indices, err := findLinks(text, linkRegex)
355✔
36
        if err != nil {
355✔
37
                return "", err
×
38
        }
×
39
        if len(indices) == 0 {
648✔
40
                return text, nil
293✔
41
        }
293✔
42
        for i := len(indices) - 2; i >= 0; i -= 2 {
188✔
43
                start, end := indices[i], indices[i+1]
126✔
44
                link := text[start+1 : end-1]
126✔
45

126✔
46
                content, ok, err := proc.refToPlaceholder(link, elems, modElems, true)
126✔
47
                if err != nil {
126✔
48
                        return "", err
×
49
                }
×
50
                if !ok {
126✔
51
                        continue
×
52
                }
53
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
126✔
54
        }
55
        return text, nil
62✔
56
}
57

58
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
34✔
59
        indices, err := findLinks(text, linkRegex)
34✔
60
        if err != nil {
34✔
61
                return "", err
×
62
        }
×
63
        if len(indices) == 0 {
54✔
64
                return text, nil
20✔
65
        }
20✔
66
        for i := len(indices) - 2; i >= 0; i -= 2 {
130✔
67
                start, end := indices[i], indices[i+1]
116✔
68
                link := text[start+1 : end-1]
116✔
69

116✔
70
                entry, linkText, parts, ok, err := proc.placeholderToLink(link, elems, modElems, proc.Config.ShortLinks)
116✔
71
                if err != nil {
116✔
72
                        return "", err
×
73
                }
×
74
                if !ok {
116✔
75
                        continue
×
76
                }
77

78
                var basePath string
116✔
79
                if entry.IsSection {
198✔
80
                        basePath = path.Join(parts[:len(parts)-1]...)
82✔
81
                } else {
116✔
82
                        basePath = path.Join(parts...)
34✔
83
                }
34✔
84

85
                pathStr := proc.Formatter.ToLinkPath(basePath, entry.Kind)
116✔
86
                if entry.IsSection {
198✔
87
                        pathStr += parts[len(parts)-1]
82✔
88
                }
82✔
89
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
116✔
90
        }
91
        return text, nil
14✔
92
}
93

94
func (proc *Processor) placeholderToLink(link string, elems []string, modElems int, shorten bool) (entry *elemPath, text string, parts []string, ok bool, err error) {
116✔
95
        linkParts := strings.SplitN(link, " ", 2)
116✔
96
        entry, text, parts, ok, err = proc.placeholderToRelLink(linkParts[0], elems, modElems)
116✔
97
        if err != nil {
116✔
98
                return
×
99
        }
×
100
        if !ok {
116✔
101
                return
×
102
        }
×
103
        if len(linkParts) > 1 {
117✔
104
                text = linkParts[1]
1✔
105
        } else {
116✔
106
                if shorten {
230✔
107
                        textParts := strings.Split(text, ".")
115✔
108
                        if entry.IsSection && entry.Kind != "package" && entry.Kind != "module" {
166✔
109
                                text = strings.Join(textParts[len(textParts)-2:], ".")
51✔
110
                        } else {
115✔
111
                                text = textParts[len(textParts)-1]
64✔
112
                        }
64✔
113
                }
114
                text = fmt.Sprintf("`%s`", text)
115✔
115
        }
116
        return
116✔
117
}
118

119
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool, error) {
116✔
120
        elemPath, ok := proc.linkTargets[link]
116✔
121
        if !ok {
116✔
122
                err := proc.warnOrError("Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
123
                return nil, "", nil, false, err
×
124
        }
×
125
        skip := 0
116✔
126
        for range modElems {
262✔
127
                if skip >= len(elemPath.Elements) {
147✔
128
                        break
1✔
129
                }
130
                if elemPath.Elements[skip] == elems[skip] {
288✔
131
                        skip++
143✔
132
                } else {
145✔
133
                        break
2✔
134
                }
135
        }
136

137
        // redirect link to re-name by re-export
138
        link = proc.renameInLink(link, &elemPath)
116✔
139

116✔
140
        fullPath := []string{}
116✔
141
        for range modElems - skip {
119✔
142
                fullPath = append(fullPath, "..")
3✔
143
        }
3✔
144
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
116✔
145
        if len(fullPath) == 0 {
118✔
146
                fullPath = []string{"."}
2✔
147
        }
2✔
148

149
        return &elemPath, link, fullPath, true, nil
116✔
150
}
151

152
func (proc *Processor) renameInLink(link string, elems *elemPath) string {
116✔
153
        if len(proc.renameExports) == 0 {
124✔
154
                return link
8✔
155
        }
8✔
156

157
        maxDepth := len(elems.Elements)
108✔
158
        if elems.IsSection {
188✔
159
                maxDepth -= 1
80✔
160
        }
80✔
161

162
        newLink := strings.Split(link, ".")
108✔
163
        dotPos := 0
108✔
164
        currDepth := 0
108✔
165
        changed := false
108✔
166
        for currDepth < len(elems.Elements) {
410✔
167
                idx := strings.IndexRune(link[dotPos:], '.')
302✔
168
                if idx < 0 {
410✔
169
                        idx = len(link) - dotPos
108✔
170
                }
108✔
171
                subLink := link[:dotPos+idx]
302✔
172
                if renamed, ok := proc.renameExports[subLink]; ok {
374✔
173
                        if currDepth < maxDepth {
122✔
174
                                newName := toFileName(renamed)
50✔
175
                                elems.Elements[currDepth] = newName
50✔
176
                        }
50✔
177
                        newLink[currDepth] = renamed
72✔
178
                        changed = true
72✔
179
                }
180
                dotPos += idx + 1
302✔
181
                currDepth++
302✔
182
        }
183
        if changed {
180✔
184
                return strings.Join(newLink, ".")
72✔
185
        }
72✔
186
        return link
36✔
187
}
188

189
func (proc *Processor) refToPlaceholder(link string, elems []string, modElems int, redirect bool) (string, bool, error) {
128✔
190
        linkParts := strings.SplitN(link, " ", 2)
128✔
191

128✔
192
        var placeholder string
128✔
193
        var ok bool
128✔
194
        var err error
128✔
195
        if strings.HasPrefix(link, ".") {
234✔
196
                placeholder, ok, err = proc.refToPlaceholderRel(linkParts[0], elems, modElems, redirect)
106✔
197
        } else {
128✔
198
                placeholder, ok, err = proc.refToPlaceholderAbs(linkParts[0], elems, redirect)
22✔
199
        }
22✔
200
        if err != nil {
128✔
201
                return "", false, err
×
202
        }
×
203
        if !ok {
128✔
204
                return "", false, nil
×
205
        }
×
206

207
        if len(linkParts) > 1 {
129✔
208
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true, nil
1✔
209
        } else {
128✔
210
                return placeholder, true, nil
127✔
211
        }
127✔
212
}
213

214
func (proc *Processor) refToPlaceholderRel(link string, elems []string, modElems int, redirect bool) (string, bool, error) {
106✔
215
        dots := 0
106✔
216
        for strings.HasPrefix(link[dots:], ".") {
217✔
217
                dots++
111✔
218
        }
111✔
219
        if dots > modElems {
106✔
220
                err := proc.warnOrError("Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
221
                return "", false, err
×
222
        }
×
223
        linkText := link[dots:]
106✔
224
        subElems := elems[:modElems-(dots-1)]
106✔
225
        var fullLink string
106✔
226
        if len(subElems) == 0 {
106✔
227
                fullLink = linkText
×
228
        } else {
106✔
229
                fullLink = strings.Join(subElems, ".") + "." + linkText
106✔
230
        }
106✔
231

232
        if !redirect {
108✔
233
                return fullLink, true, nil
2✔
234
        }
2✔
235

236
        placeholder, ok := proc.linkExports[fullLink]
104✔
237
        if !ok {
104✔
238
                err := proc.warnOrError("Can't resolve cross ref (rel) '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
×
239
                return "", false, err
×
240
        }
×
241
        return placeholder, true, nil
104✔
242
}
243

244
func (proc *Processor) refToPlaceholderAbs(link string, elems []string, redirect bool) (string, bool, error) {
22✔
245
        if !redirect {
22✔
NEW
246
                return link, true, nil
×
NEW
247
        }
×
248
        placeholder, ok := proc.linkExports[link]
22✔
249
        if !ok {
22✔
250
                err := proc.warnOrError("Can't resolve cross ref (abs) '%s' in %s", link, strings.Join(elems, "."))
×
251
                return "", false, err
×
252
        }
×
253
        return placeholder, true, nil
22✔
254
}
255

256
func findLinks(text string, regex *regexp.Regexp) ([]int, error) {
399✔
257
        links := []int{}
399✔
258
        results := regex.FindAllStringSubmatchIndex(text, -1)
399✔
259
        for _, r := range results {
855✔
260
                if r[6] >= 0 {
740✔
261
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
322✔
262
                                continue
38✔
263
                        }
264
                        links = append(links, r[6], r[7])
246✔
265
                }
266
        }
267

268
        return links, nil
399✔
269
}
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