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

mlange-42 / modo / 12855591956

19 Jan 2025 05:15PM CUT coverage: 58.921% (-0.03%) from 58.946%
12855591956

Pull #68

github

web-flow
Merge 3e8a1725d into 9b764dda7
Pull Request #68: Strict mode, check re-exports

80 of 109 new or added lines in 7 files covered. (73.39%)

5 existing lines in 1 file now uncovered.

819 of 1390 relevant lines covered (58.92%)

7.89 hits per line

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

67.89
/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
// Replaces cross-refs by placeholders, recursively.
13
//
14
// Runs on the original docs, to packages can't have structs, traits or function yet.
15
func (proc *Processor) processLinksPackage(p *Package, elems []string) error {
4✔
16
        newElems := appendNew(elems, p.GetName())
4✔
17

4✔
18
        var err error
4✔
19
        p.Summary, err = proc.replaceRefs(p.Summary, newElems, len(newElems))
4✔
20
        if err != nil {
4✔
21
                return err
×
22
        }
×
23
        p.Description, err = proc.replaceRefs(p.Description, newElems, len(newElems))
4✔
24
        if err != nil {
4✔
25
                return err
×
26
        }
×
27

28
        for _, pkg := range p.Packages {
4✔
29
                proc.processLinksPackage(pkg, newElems)
×
30
        }
×
31
        for _, mod := range p.Modules {
9✔
32
                proc.processLinksModule(mod, newElems)
5✔
33
        }
5✔
34
        // Runs on the original docs, to packages can't have structs, traits or function yet.
35
        return nil
4✔
36
}
37

38
func (proc *Processor) processLinksModule(m *Module, elems []string) error {
5✔
39
        newElems := appendNew(elems, m.GetName())
5✔
40

5✔
41
        var err error
5✔
42
        m.Summary, err = proc.replaceRefs(m.Summary, newElems, len(newElems))
5✔
43
        if err != nil {
5✔
44
                return err
×
45
        }
×
46
        m.Description, err = proc.replaceRefs(m.Description, newElems, len(newElems))
5✔
47
        if err != nil {
5✔
48
                return err
×
49
        }
×
50

51
        for _, a := range m.Aliases {
6✔
52
                err := proc.processLinksModuleAlias(a, newElems)
1✔
53
                if err != nil {
1✔
54
                        return err
×
55
                }
×
56
        }
57
        for _, f := range m.Functions {
7✔
58
                err := proc.processLinksFunction(f, newElems)
2✔
59
                if err != nil {
2✔
60
                        return err
×
61
                }
×
62
        }
63
        for _, s := range m.Structs {
8✔
64
                err := proc.processLinksStruct(s, newElems)
3✔
65
                if err != nil {
3✔
66
                        return err
×
67
                }
×
68
        }
69
        for _, tr := range m.Traits {
7✔
70
                err := proc.processLinksTrait(tr, newElems)
2✔
71
                if err != nil {
2✔
72
                        return err
×
73
                }
×
74
        }
75

76
        return nil
5✔
77
}
78

79
func (proc *Processor) processLinksStruct(s *Struct, elems []string) error {
3✔
80
        newElems := appendNew(elems, s.GetName())
3✔
81

3✔
82
        var err error
3✔
83
        s.Summary, err = proc.replaceRefs(s.Summary, newElems, len(elems))
3✔
84
        if err != nil {
3✔
85
                return err
×
86
        }
×
87
        s.Description, err = proc.replaceRefs(s.Description, newElems, len(elems))
3✔
88
        if err != nil {
3✔
89
                return err
×
90
        }
×
91
        s.Deprecated, err = proc.replaceRefs(s.Deprecated, newElems, len(elems))
3✔
92
        if err != nil {
3✔
93
                return err
×
94
        }
×
95

96
        for _, a := range s.Aliases {
4✔
97
                a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
1✔
98
                if err != nil {
1✔
99
                        return err
×
100
                }
×
101
                a.Deprecated, err = proc.replaceRefs(a.Deprecated, newElems, len(elems))
1✔
102
                if err != nil {
1✔
103
                        return err
×
104
                }
×
105
        }
106
        for _, p := range s.Parameters {
4✔
107
                p.Description, err = proc.replaceRefs(p.Description, newElems, len(elems))
1✔
108
                if err != nil {
1✔
109
                        return err
×
110
                }
×
111
        }
112
        for _, f := range s.Fields {
5✔
113
                f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
2✔
114
                if err != nil {
2✔
115
                        return err
×
116
                }
×
117
                f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
2✔
118
                if err != nil {
2✔
119
                        return err
×
120
                }
×
121
        }
122
        for _, f := range s.Functions {
4✔
123
                if err := proc.processLinksMethod(f, elems); err != nil {
1✔
124
                        return err
×
125
                }
×
126
        }
127

128
        return nil
3✔
129
}
130

131
func (proc *Processor) processLinksTrait(tr *Trait, elems []string) error {
2✔
132
        newElems := appendNew(elems, tr.GetName())
2✔
133

2✔
134
        var err error
2✔
135
        tr.Summary, err = proc.replaceRefs(tr.Summary, newElems, len(elems))
2✔
136
        if err != nil {
2✔
137
                return err
×
138
        }
×
139
        tr.Description, err = proc.replaceRefs(tr.Description, newElems, len(elems))
2✔
140
        if err != nil {
2✔
141
                return err
×
142
        }
×
143
        tr.Deprecated, err = proc.replaceRefs(tr.Deprecated, newElems, len(elems))
2✔
144
        if err != nil {
2✔
145
                return err
×
146
        }
×
147

148
        // TODO: add when traits support parameters
149
        /*for _, p := range tr.Parameters {
150
                p.Description, err = replaceLinks(p.Description, newElems, len(elems), lookup, t)
151
                if err != nil {
152
                        return err
153
                }
154
        }*/
155
        for _, f := range tr.Fields {
3✔
156
                f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
1✔
157
                if err != nil {
1✔
158
                        return err
×
159
                }
×
160
                f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
1✔
161
                if err != nil {
1✔
162
                        return err
×
163
                }
×
164
        }
165
        for _, f := range tr.Functions {
3✔
166
                if err := proc.processLinksMethod(f, elems); err != nil {
1✔
167
                        return err
×
168
                }
×
169
        }
170

171
        return nil
2✔
172
}
173

174
func (proc *Processor) processLinksFunction(f *Function, elems []string) error {
4✔
175
        newElems := appendNew(elems, f.GetName())
4✔
176

4✔
177
        var err error
4✔
178
        f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
4✔
179
        if err != nil {
4✔
180
                return err
×
181
        }
×
182
        f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
4✔
183
        if err != nil {
4✔
184
                return err
×
185
        }
×
186
        f.Deprecated, err = proc.replaceRefs(f.Deprecated, newElems, len(elems))
4✔
187
        if err != nil {
4✔
188
                return err
×
189
        }
×
190
        f.ReturnsDoc, err = proc.replaceRefs(f.ReturnsDoc, newElems, len(elems))
4✔
191
        if err != nil {
4✔
192
                return err
×
193
        }
×
194
        f.RaisesDoc, err = proc.replaceRefs(f.RaisesDoc, newElems, len(elems))
4✔
195
        if err != nil {
4✔
196
                return err
×
197
        }
×
198

199
        for _, a := range f.Args {
5✔
200
                a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
1✔
201
                if err != nil {
1✔
202
                        return err
×
203
                }
×
204
        }
205
        for _, p := range f.Parameters {
5✔
206
                p.Description, err = proc.replaceRefs(p.Description, newElems, len(elems))
1✔
207
                if err != nil {
1✔
208
                        return err
×
209
                }
×
210
        }
211

212
        for _, o := range f.Overloads {
6✔
213
                err := proc.processLinksFunction(o, elems)
2✔
214
                if err != nil {
2✔
215
                        return err
×
216
                }
×
217
        }
218

219
        return nil
4✔
220
}
221

222
func (proc *Processor) processLinksModuleAlias(a *Alias, elems []string) error {
1✔
223
        newElems := appendNew(elems, a.GetName())
1✔
224

1✔
225
        var err error
1✔
226
        a.Summary, err = proc.replaceRefs(a.Summary, newElems, len(elems))
1✔
227
        if err != nil {
1✔
228
                return err
×
229
        }
×
230
        a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
1✔
231
        if err != nil {
1✔
232
                return err
×
233
        }
×
234
        a.Deprecated, err = proc.replaceRefs(a.Deprecated, newElems, len(elems))
1✔
235
        if err != nil {
1✔
236
                return err
×
237
        }
×
238
        return nil
1✔
239
}
240

241
func (proc *Processor) processLinksMethod(f *Function, elems []string) error {
4✔
242
        var err error
4✔
243
        f.Summary, err = proc.replaceRefs(f.Summary, elems, len(elems))
4✔
244
        if err != nil {
4✔
245
                return err
×
246
        }
×
247
        f.Description, err = proc.replaceRefs(f.Description, elems, len(elems))
4✔
248
        if err != nil {
4✔
249
                return err
×
250
        }
×
251
        f.Deprecated, err = proc.replaceRefs(f.Deprecated, elems, len(elems))
4✔
252
        if err != nil {
4✔
253
                return err
×
254
        }
×
255
        f.ReturnsDoc, err = proc.replaceRefs(f.ReturnsDoc, elems, len(elems))
4✔
256
        if err != nil {
4✔
257
                return err
×
258
        }
×
259
        f.RaisesDoc, err = proc.replaceRefs(f.RaisesDoc, elems, len(elems))
4✔
260
        if err != nil {
4✔
261
                return err
×
262
        }
×
263

264
        for _, a := range f.Args {
6✔
265
                a.Description, err = proc.replaceRefs(a.Description, elems, len(elems))
2✔
266
                if err != nil {
2✔
267
                        return err
×
268
                }
×
269
        }
270
        for _, p := range f.Parameters {
6✔
271
                p.Description, err = proc.replaceRefs(p.Description, elems, len(elems))
2✔
272
                if err != nil {
2✔
273
                        return err
×
274
                }
×
275
        }
276

277
        for _, o := range f.Overloads {
6✔
278
                err := proc.processLinksMethod(o, elems)
2✔
279
                if err != nil {
2✔
280
                        return err
×
281
                }
×
282
        }
283

284
        return nil
4✔
285
}
286

287
func (proc *Processor) replaceRefs(text string, elems []string, modElems int) (string, error) {
92✔
288
        indices, err := findLinks(text)
92✔
289
        if err != nil {
92✔
290
                return "", err
×
291
        }
×
292
        if len(indices) == 0 {
182✔
293
                return text, nil
90✔
294
        }
90✔
295
        for i := len(indices) - 2; i >= 0; i -= 2 {
10✔
296
                start, end := indices[i], indices[i+1]
8✔
297
                link := text[start+1 : end-1]
8✔
298

8✔
299
                content, ok, err := proc.refToPlaceholder(link, elems, modElems)
8✔
300
                if err != nil {
8✔
NEW
301
                        return "", err
×
NEW
302
                }
×
303
                if !ok {
8✔
304
                        continue
×
305
                }
306
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
8✔
307
        }
308
        return text, nil
2✔
309
}
310

311
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
16✔
312
        indices, err := findLinks(text)
16✔
313
        if err != nil {
16✔
314
                return "", err
×
315
        }
×
316
        if len(indices) == 0 {
30✔
317
                return text, nil
14✔
318
        }
14✔
319
        for i := len(indices) - 2; i >= 0; i -= 2 {
10✔
320
                start, end := indices[i], indices[i+1]
8✔
321
                link := text[start+1 : end-1]
8✔
322

8✔
323
                entry, linkText, parts, ok, err := proc.placeholderToLink(link, elems, modElems, proc.Config.ShortLinks)
8✔
324
                if err != nil {
8✔
NEW
325
                        return "", err
×
NEW
326
                }
×
327
                if !ok {
8✔
328
                        continue
×
329
                }
330

331
                var basePath string
8✔
332
                if entry.IsSection {
10✔
333
                        basePath = path.Join(parts[:len(parts)-1]...)
2✔
334
                } else {
8✔
335
                        basePath = path.Join(parts...)
6✔
336
                }
6✔
337

338
                pathStr, err := proc.Formatter.ToLinkPath(basePath, entry.Kind)
8✔
339
                if err != nil {
8✔
340
                        return "", err
×
341
                }
×
342
                if entry.IsSection {
10✔
343
                        pathStr += parts[len(parts)-1]
2✔
344
                }
2✔
345
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
8✔
346
        }
347
        return text, nil
2✔
348
}
349

350
func (proc *Processor) placeholderToLink(link string, elems []string, modElems int, shorten bool) (entry *elemPath, text string, parts []string, ok bool, err error) {
8✔
351
        linkParts := strings.SplitN(link, " ", 2)
8✔
352
        entry, text, parts, ok, err = proc.placeholderToRelLink(linkParts[0], elems, modElems)
8✔
353
        if err != nil {
8✔
NEW
354
                return
×
NEW
355
        }
×
356
        if !ok {
8✔
357
                return
×
358
        }
×
359
        if len(linkParts) > 1 {
9✔
360
                text = linkParts[1]
1✔
361
        } else {
8✔
362
                if shorten {
14✔
363
                        textParts := strings.Split(text, ".")
7✔
364
                        if entry.IsSection {
8✔
365
                                text = strings.Join(textParts[len(textParts)-2:], ".")
1✔
366
                        } else {
7✔
367
                                text = textParts[len(textParts)-1]
6✔
368
                        }
6✔
369
                }
370
                text = fmt.Sprintf("`%s`", text)
7✔
371
        }
372
        return
8✔
373
}
374

375
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool, error) {
8✔
376
        elemPath, ok := proc.linkTargets[link]
8✔
377
        if !ok {
8✔
NEW
378
                err := proc.warnOrError("Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
NEW
379
                return nil, "", nil, false, err
×
UNCOV
380
        }
×
381
        skip := 0
8✔
382
        for range modElems {
22✔
383
                if len(elemPath.Elements) <= skip {
15✔
384
                        break
1✔
385
                }
386
                if elemPath.Elements[skip] == elems[skip] {
24✔
387
                        skip++
11✔
388
                } else {
13✔
389
                        break
2✔
390
                }
391
        }
392
        fullPath := []string{}
8✔
393
        for range modElems - skip {
11✔
394
                fullPath = append(fullPath, "..")
3✔
395
        }
3✔
396
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
8✔
397
        if len(fullPath) == 0 {
8✔
398
                fullPath = append(fullPath, ".")
×
399
        }
×
400

401
        return &elemPath, link, fullPath, true, nil
8✔
402
}
403

404
func (proc *Processor) refToPlaceholder(link string, elems []string, modElems int) (string, bool, error) {
8✔
405
        linkParts := strings.SplitN(link, " ", 2)
8✔
406

8✔
407
        var placeholder string
8✔
408
        var ok bool
8✔
409
        var err error
8✔
410
        if strings.HasPrefix(link, ".") {
14✔
411
                placeholder, ok, err = proc.refToPlaceholderRel(linkParts[0], elems, modElems)
6✔
412
        } else {
8✔
413
                placeholder, ok, err = proc.refToPlaceholderAbs(linkParts[0], elems)
2✔
414
        }
2✔
415
        if err != nil {
8✔
NEW
416
                return "", false, err
×
UNCOV
417
        }
×
418
        if !ok {
8✔
NEW
419
                return "", false, nil
×
420
        }
×
421

422
        if len(linkParts) > 1 {
9✔
423
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true, nil
1✔
424
        } else {
8✔
425
                return placeholder, true, nil
7✔
426
        }
7✔
427
}
428

429
func (proc *Processor) refToPlaceholderRel(link string, elems []string, modElems int) (string, bool, error) {
6✔
430
        dots := 0
6✔
431
        for strings.HasPrefix(link[dots:], ".") {
13✔
432
                dots++
7✔
433
        }
7✔
434
        if dots > modElems {
6✔
NEW
435
                err := proc.warnOrError("Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
NEW
436
                return "", false, err
×
UNCOV
437
        }
×
438
        linkText := link[dots:]
6✔
439
        subElems := elems[:modElems-(dots-1)]
6✔
440
        var fullLink string
6✔
441
        if len(subElems) == 0 {
6✔
442
                fullLink = linkText
×
443
        } else {
6✔
444
                fullLink = strings.Join(subElems, ".") + "." + linkText
6✔
445
        }
6✔
446

447
        placeholder, ok := proc.linkExports[fullLink]
6✔
448
        if !ok {
6✔
NEW
449
                err := proc.warnOrError("Can't resolve cross ref (rel) '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
×
NEW
450
                return "", false, err
×
UNCOV
451
        }
×
452
        return placeholder, true, nil
6✔
453
}
454

455
func (proc *Processor) refToPlaceholderAbs(link string, elems []string) (string, bool, error) {
2✔
456
        placeholder, ok := proc.linkExports[link]
2✔
457
        if !ok {
2✔
NEW
458
                err := proc.warnOrError("Can't resolve cross ref (abs) '%s' in %s", link, strings.Join(elems, "."))
×
NEW
459
                return "", false, err
×
UNCOV
460
        }
×
461
        return placeholder, true, nil
2✔
462
}
463

464
func findLinks(text string) ([]int, error) {
109✔
465
        re, err := regexp.Compile(regexString)
109✔
466
        if err != nil {
109✔
467
                return nil, err
×
468
        }
×
469
        links := []int{}
109✔
470
        results := re.FindAllStringSubmatchIndex(text, -1)
109✔
471
        for _, r := range results {
178✔
472
                if r[6] >= 0 {
100✔
473
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
44✔
474
                                continue
13✔
475
                        }
476
                        links = append(links, r[6], r[7])
18✔
477
                }
478
        }
479

480
        return links, nil
109✔
481
}
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