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

mlange-42 / modo / 12810588007

16 Jan 2025 02:06PM CUT coverage: 36.851% (+0.3%) from 36.569%
12810588007

push

github

web-flow
Error on no exports, silence help (#43)

20 of 33 new or added lines in 4 files covered. (60.61%)

2 existing lines in 2 files now uncovered.

447 of 1213 relevant lines covered (36.85%)

2.66 hits per line

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

17.88
/document/links.go
1
package document
2

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

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

13
func findLinks(text string) ([]int, error) {
2✔
14
        re, err := regexp.Compile(regexString)
2✔
15
        if err != nil {
2✔
16
                return nil, err
×
17
        }
×
18
        links := []int{}
2✔
19
        results := re.FindAllStringSubmatchIndex(text, -1)
2✔
20
        for _, r := range results {
12✔
21
                if r[6] >= 0 {
18✔
22
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
9✔
23
                                continue
1✔
24
                        }
25
                        links = append(links, r[6], r[7])
7✔
26
                }
27
        }
28

29
        return links, nil
2✔
30
}
31

32
func (proc *Processor) ProcessLinks() error {
×
NEW
33
        err := proc.filterPackages()
×
NEW
34
        if err != nil {
×
NEW
35
                return err
×
NEW
36
        }
×
37
        proc.collectPaths()
×
38

×
39
        if !proc.UseExports {
×
40
                for k := range proc.linkTargets {
×
41
                        proc.linkExports[k] = k
×
42
                }
×
43
        }
44
        if err := proc.processLinksPackage(proc.Docs.Decl, []string{}, true); err != nil {
×
45
                return err
×
46
        }
×
47
        if err := proc.processLinksPackage(proc.ExportDocs.Decl, []string{}, false); err != nil {
×
48
                return err
×
49
        }
×
50
        return nil
×
51
}
52

53
func (proc *Processor) processLinksPackage(p *Package, elems []string, firstPass bool) error {
×
54
        newElems := appendNew(elems, p.GetName())
×
55

×
56
        var err error
×
57
        p.Summary, err = proc.replaceLinks(p.Summary, newElems, len(newElems), firstPass)
×
58
        if err != nil {
×
59
                return err
×
60
        }
×
61
        p.Description, err = proc.replaceLinks(p.Description, newElems, len(newElems), firstPass)
×
62
        if err != nil {
×
63
                return err
×
64
        }
×
65

66
        for _, pkg := range p.Packages {
×
67
                proc.processLinksPackage(pkg, newElems, firstPass)
×
68
        }
×
69
        for _, mod := range p.Modules {
×
70
                proc.processLinksModule(mod, newElems, firstPass)
×
71
        }
×
72

73
        for _, f := range p.Functions {
×
74
                err := proc.processLinksFunction(f, newElems, firstPass)
×
75
                if err != nil {
×
76
                        return err
×
77
                }
×
78
        }
79
        for _, s := range p.Structs {
×
80
                err := proc.processLinksStruct(s, newElems, firstPass)
×
81
                if err != nil {
×
82
                        return err
×
83
                }
×
84
        }
85
        for _, tr := range p.Traits {
×
86
                err := proc.processLinksTrait(tr, newElems, firstPass)
×
87
                if err != nil {
×
88
                        return err
×
89
                }
×
90
        }
91

92
        return nil
×
93
}
94

95
func (proc *Processor) processLinksModule(m *Module, elems []string, firstPass bool) error {
×
96
        newElems := appendNew(elems, m.GetName())
×
97

×
98
        var err error
×
99
        m.Summary, err = proc.replaceLinks(m.Summary, newElems, len(newElems), firstPass)
×
100
        if err != nil {
×
101
                return err
×
102
        }
×
103
        m.Description, err = proc.replaceLinks(m.Description, newElems, len(newElems), firstPass)
×
104
        if err != nil {
×
105
                return err
×
106
        }
×
107

108
        for _, f := range m.Functions {
×
109
                err := proc.processLinksFunction(f, newElems, firstPass)
×
110
                if err != nil {
×
111
                        return err
×
112
                }
×
113
        }
114
        for _, s := range m.Structs {
×
115
                err := proc.processLinksStruct(s, newElems, firstPass)
×
116
                if err != nil {
×
117
                        return err
×
118
                }
×
119
        }
120
        for _, tr := range m.Traits {
×
121
                err := proc.processLinksTrait(tr, newElems, firstPass)
×
122
                if err != nil {
×
123
                        return err
×
124
                }
×
125
        }
126

127
        return nil
×
128
}
129

130
func (proc *Processor) processLinksStruct(s *Struct, elems []string, firstPass bool) error {
×
131
        newElems := appendNew(elems, s.GetName())
×
132

×
133
        var err error
×
134
        s.Summary, err = proc.replaceLinks(s.Summary, newElems, len(elems), firstPass)
×
135
        if err != nil {
×
136
                return err
×
137
        }
×
138
        s.Description, err = proc.replaceLinks(s.Description, newElems, len(elems), firstPass)
×
139
        if err != nil {
×
140
                return err
×
141
        }
×
142

143
        for _, p := range s.Parameters {
×
144
                p.Description, err = proc.replaceLinks(p.Description, newElems, len(elems), firstPass)
×
145
                if err != nil {
×
146
                        return err
×
147
                }
×
148
        }
149
        for _, f := range s.Fields {
×
150
                f.Summary, err = proc.replaceLinks(f.Summary, newElems, len(elems), firstPass)
×
151
                if err != nil {
×
152
                        return err
×
153
                }
×
154
                f.Description, err = proc.replaceLinks(f.Description, newElems, len(elems), firstPass)
×
155
                if err != nil {
×
156
                        return err
×
157
                }
×
158
        }
159
        for _, f := range s.Functions {
×
160
                if err := proc.processLinksMethod(f, elems, firstPass); err != nil {
×
161
                        return err
×
162
                }
×
163
        }
164

165
        return nil
×
166
}
167

168
func (proc *Processor) processLinksTrait(tr *Trait, elems []string, firstPass bool) error {
×
169
        newElems := appendNew(elems, tr.GetName())
×
170

×
171
        var err error
×
172
        tr.Summary, err = proc.replaceLinks(tr.Summary, newElems, len(elems), firstPass)
×
173
        if err != nil {
×
174
                return err
×
175
        }
×
176
        tr.Description, err = proc.replaceLinks(tr.Description, newElems, len(elems), firstPass)
×
177
        if err != nil {
×
178
                return err
×
179
        }
×
180

181
        // TODO: add when traits support parameters
182
        /*for _, p := range tr.Parameters {
183
                p.Description, err = replaceLinks(p.Description, newElems, len(elems), lookup, t)
184
                if err != nil {
185
                        return err
186
                }
187
        }*/
188
        for _, f := range tr.Fields {
×
189
                f.Summary, err = proc.replaceLinks(f.Summary, newElems, len(elems), firstPass)
×
190
                if err != nil {
×
191
                        return err
×
192
                }
×
193
                f.Description, err = proc.replaceLinks(f.Description, newElems, len(elems), firstPass)
×
194
                if err != nil {
×
195
                        return err
×
196
                }
×
197
        }
198
        for _, f := range tr.Functions {
×
199
                if err := proc.processLinksMethod(f, elems, firstPass); err != nil {
×
200
                        return err
×
201
                }
×
202
        }
203

204
        return nil
×
205
}
206

207
func (proc *Processor) processLinksFunction(f *Function, elems []string, firstPass bool) error {
×
208
        newElems := appendNew(elems, f.GetName())
×
209

×
210
        var err error
×
211
        f.Summary, err = proc.replaceLinks(f.Summary, newElems, len(elems), firstPass)
×
212
        if err != nil {
×
213
                return err
×
214
        }
×
215
        f.Description, err = proc.replaceLinks(f.Description, newElems, len(elems), firstPass)
×
216
        if err != nil {
×
217
                return err
×
218
        }
×
219
        f.ReturnsDoc, err = proc.replaceLinks(f.ReturnsDoc, newElems, len(elems), firstPass)
×
220
        if err != nil {
×
221
                return err
×
222
        }
×
223
        f.RaisesDoc, err = proc.replaceLinks(f.RaisesDoc, newElems, len(elems), firstPass)
×
224
        if err != nil {
×
225
                return err
×
226
        }
×
227

228
        for _, a := range f.Args {
×
229
                a.Description, err = proc.replaceLinks(a.Description, newElems, len(elems), firstPass)
×
230
                if err != nil {
×
231
                        return err
×
232
                }
×
233
        }
234
        for _, p := range f.Parameters {
×
235
                p.Description, err = proc.replaceLinks(p.Description, newElems, len(elems), firstPass)
×
236
                if err != nil {
×
237
                        return err
×
238
                }
×
239
        }
240

241
        for _, o := range f.Overloads {
×
242
                err := proc.processLinksFunction(o, elems, firstPass)
×
243
                if err != nil {
×
244
                        return err
×
245
                }
×
246
        }
247

248
        return nil
×
249
}
250

251
func (proc *Processor) processLinksMethod(f *Function, elems []string, firstPass bool) error {
×
252
        var err error
×
253
        f.Summary, err = proc.replaceLinks(f.Summary, elems, len(elems), firstPass)
×
254
        if err != nil {
×
255
                return err
×
256
        }
×
257
        f.Description, err = proc.replaceLinks(f.Description, elems, len(elems), firstPass)
×
258
        if err != nil {
×
259
                return err
×
260
        }
×
261
        f.ReturnsDoc, err = proc.replaceLinks(f.ReturnsDoc, elems, len(elems), firstPass)
×
262
        if err != nil {
×
263
                return err
×
264
        }
×
265
        f.RaisesDoc, err = proc.replaceLinks(f.RaisesDoc, elems, len(elems), firstPass)
×
266
        if err != nil {
×
267
                return err
×
268
        }
×
269

270
        for _, a := range f.Args {
×
271
                a.Description, err = proc.replaceLinks(a.Description, elems, len(elems), firstPass)
×
272
                if err != nil {
×
273
                        return err
×
274
                }
×
275
        }
276
        for _, p := range f.Parameters {
×
277
                p.Description, err = proc.replaceLinks(p.Description, elems, len(elems), firstPass)
×
278
                if err != nil {
×
279
                        return err
×
280
                }
×
281
        }
282

283
        for _, o := range f.Overloads {
×
284
                err := proc.processLinksMethod(o, elems, firstPass)
×
285
                if err != nil {
×
286
                        return err
×
287
                }
×
288
        }
289

290
        return nil
×
291
}
292

293
func (proc *Processor) replaceLinks(text string, elems []string, modElems int, firstPass bool) (string, error) {
1✔
294
        if firstPass {
2✔
295
                return proc.replaceLinksFirstPass(text, elems, modElems)
1✔
296
        }
1✔
297
        return proc.replaceLinksSecondPass(text, elems, modElems)
×
298
}
299

300
func (proc *Processor) replaceLinksSecondPass(text string, elems []string, modElems int) (string, error) {
×
301
        indices, err := findLinks(text)
×
302
        if err != nil {
×
303
                return "", err
×
304
        }
×
305
        if len(indices) == 0 {
×
306
                return text, nil
×
307
        }
×
308
        for i := len(indices) - 2; i >= 0; i -= 2 {
×
309
                start, end := indices[i], indices[i+1]
×
310
                link := text[start+1 : end-1]
×
311

×
312
                entry, linkText, parts, ok := placeholderToLink(link, elems, modElems, proc.linkTargets, proc.ShortLinks)
×
313
                if !ok {
×
314
                        continue
×
315
                }
316

317
                var basePath string
×
318
                if entry.IsSection {
×
319
                        basePath = path.Join(parts[:len(parts)-1]...)
×
320
                } else {
×
321
                        basePath = path.Join(parts...)
×
322
                }
×
323

324
                pathStr, err := proc.Formatter.ToLinkPath(basePath, entry.Kind)
×
325
                if err != nil {
×
326
                        return "", err
×
327
                }
×
328
                if entry.IsSection {
×
329
                        pathStr += parts[len(parts)-1]
×
330
                }
×
331
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
×
332
        }
333
        return text, nil
×
334
}
335

336
func (proc *Processor) replaceLinksFirstPass(text string, elems []string, modElems int) (string, error) {
1✔
337
        indices, err := findLinks(text)
1✔
338
        if err != nil {
1✔
339
                return "", err
×
340
        }
×
341
        if len(indices) == 0 {
1✔
342
                return text, nil
×
343
        }
×
344
        for i := len(indices) - 2; i >= 0; i -= 2 {
6✔
345
                start, end := indices[i], indices[i+1]
5✔
346
                link := text[start+1 : end-1]
5✔
347

5✔
348
                content, ok := linkToPlaceholder(link, elems, modElems, proc.linkExports)
5✔
349
                if !ok {
10✔
350
                        continue
5✔
351
                }
352
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
×
353
        }
354
        return text, nil
1✔
355
}
356

357
func placeholderToLink(link string, elems []string, modElems int, lookup map[string]elemPath, shorten bool) (entry *elemPath, text string, parts []string, ok bool) {
×
358
        linkParts := strings.SplitN(link, " ", 2)
×
359
        entry, text, parts, ok = placeholderToAbsLink(linkParts[0], elems, modElems, lookup)
×
360
        if !ok {
×
361
                return
×
362
        }
×
363
        if len(linkParts) > 1 {
×
364
                text = linkParts[1]
×
365
        } else {
×
366
                if shorten {
×
367
                        textParts := strings.Split(text, ".")
×
368
                        if entry.IsSection {
×
369
                                text = strings.Join(textParts[len(textParts)-2:], ".")
×
370
                        } else {
×
371
                                text = textParts[len(textParts)-1]
×
372
                        }
×
373
                }
374
                text = fmt.Sprintf("`%s`", text)
×
375
        }
376
        return
×
377
}
378

379
func placeholderToAbsLink(link string, elems []string, modElems int, lookup map[string]elemPath) (*elemPath, string, []string, bool) {
×
380
        elemPath, ok := lookup[link]
×
381
        if !ok {
×
382
                log.Printf("WARNING: Can't resolve cross ref '%s' in %s", link, strings.Join(elems, "."))
×
383
                return nil, "", nil, false
×
384
        }
×
385
        skip := 0
×
386
        for range modElems {
×
387
                if len(elemPath.Elements) <= skip {
×
388
                        break
×
389
                }
390
                if elemPath.Elements[skip] == elems[skip] {
×
391
                        skip++
×
392
                } else {
×
393
                        break
×
394
                }
395
        }
396
        fullPath := []string{}
×
397
        for range modElems - skip {
×
398
                fullPath = append(fullPath, "..")
×
399
        }
×
400
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
×
401
        return &elemPath, link, fullPath, true
×
402
}
403

404
func linkToPlaceholder(link string, elems []string, modElems int, lookup map[string]string) (string, bool) {
5✔
405
        linkParts := strings.SplitN(link, " ", 2)
5✔
406

5✔
407
        var placeholder string
5✔
408
        var ok bool
5✔
409
        if strings.HasPrefix(link, ".") {
9✔
410
                placeholder, ok = linkToPlaceholderRel(linkParts[0], elems, modElems, lookup)
4✔
411
        } else {
5✔
412
                placeholder, ok = linkToPlaceholderAbs(linkParts[0], elems, lookup)
1✔
413
        }
1✔
414
        if !ok {
10✔
415
                return "", false
5✔
416
        }
5✔
417
        if len(linkParts) > 1 {
×
418
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true
×
419
        } else {
×
420
                return placeholder, true
×
421
        }
×
422
}
423

424
func linkToPlaceholderRel(link string, elems []string, modElems int, lookup map[string]string) (string, bool) {
4✔
425
        dots := 0
4✔
426
        for strings.HasPrefix(link[dots:], ".") {
9✔
427
                dots++
5✔
428
        }
5✔
429
        if dots > modElems {
4✔
430
                log.Printf("WARNING: Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
431
                return "", false
×
432
        }
×
433
        linkText := link[dots:]
4✔
434
        subElems := elems[:modElems-(dots-1)]
4✔
435
        var fullLink string
4✔
436
        if len(subElems) == 0 {
4✔
437
                fullLink = linkText
×
438
        } else {
4✔
439
                fullLink = strings.Join(subElems, ".") + "." + linkText
4✔
440
        }
4✔
441

442
        placeholder, ok := lookup[fullLink]
4✔
443
        if !ok {
8✔
444
                log.Printf("WARNING: Can't resolve cross ref '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
4✔
445
                return "", false
4✔
446
        }
4✔
447
        return placeholder, true
×
448
}
449

450
func linkToPlaceholderAbs(link string, elems []string, lookup map[string]string) (string, bool) {
1✔
451
        placeholder, ok := lookup[link]
1✔
452
        if !ok {
2✔
453
                log.Printf("WARNING: Can't resolve cross ref '%s' in %s", link, strings.Join(elems, "."))
1✔
454
                return "", false
1✔
455
        }
1✔
456
        return placeholder, true
×
457
}
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