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

mlange-42 / modo / 12866129702

20 Jan 2025 10:35AM CUT coverage: 60.673%. Remained the same
12866129702

push

github

web-flow
Tweak templates for consistent line breaks (#75)

901 of 1485 relevant lines covered (60.67%)

22.37 hits per line

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

68.73
/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 {
8✔
16
        newElems := appendNew(elems, p.GetName())
8✔
17

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

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

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

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

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

76
        return nil
9✔
77
}
78

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

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

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

132
        return nil
7✔
133
}
134

135
func (proc *Processor) processLinksTrait(tr *Trait, elems []string) error {
4✔
136
        newElems := appendNew(elems, tr.GetName())
4✔
137

4✔
138
        var err error
4✔
139
        tr.Summary, err = proc.replaceRefs(tr.Summary, newElems, len(elems))
4✔
140
        if err != nil {
4✔
141
                return err
×
142
        }
×
143
        tr.Description, err = proc.replaceRefs(tr.Description, newElems, len(elems))
4✔
144
        if err != nil {
4✔
145
                return err
×
146
        }
×
147
        tr.Deprecated, err = proc.replaceRefs(tr.Deprecated, newElems, len(elems))
4✔
148
        if err != nil {
4✔
149
                return err
×
150
        }
×
151

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

175
        return nil
4✔
176
}
177

178
func (proc *Processor) processLinksFunction(f *Function, elems []string) error {
8✔
179
        newElems := appendNew(elems, f.GetName())
8✔
180

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

203
        for _, a := range f.Args {
11✔
204
                a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
3✔
205
                if err != nil {
3✔
206
                        return err
×
207
                }
×
208
        }
209
        for _, p := range f.Parameters {
11✔
210
                p.Description, err = proc.replaceRefs(p.Description, newElems, len(elems))
3✔
211
                if err != nil {
3✔
212
                        return err
×
213
                }
×
214
        }
215

216
        for _, o := range f.Overloads {
12✔
217
                err := proc.processLinksFunction(o, elems)
4✔
218
                if err != nil {
4✔
219
                        return err
×
220
                }
×
221
        }
222

223
        return nil
8✔
224
}
225

226
func (proc *Processor) processLinksModuleAlias(a *Alias, elems []string) error {
5✔
227
        newElems := appendNew(elems, a.GetName())
5✔
228

5✔
229
        var err error
5✔
230
        a.Summary, err = proc.replaceRefs(a.Summary, newElems, len(elems))
5✔
231
        if err != nil {
5✔
232
                return err
×
233
        }
×
234
        a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
5✔
235
        if err != nil {
5✔
236
                return err
×
237
        }
×
238
        a.Deprecated, err = proc.replaceRefs(a.Deprecated, newElems, len(elems))
5✔
239
        if err != nil {
5✔
240
                return err
×
241
        }
×
242
        return nil
5✔
243
}
244

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

268
        for _, a := range f.Args {
30✔
269
                a.Description, err = proc.replaceRefs(a.Description, elems, len(elems))
14✔
270
                if err != nil {
14✔
271
                        return err
×
272
                }
×
273
        }
274
        for _, p := range f.Parameters {
22✔
275
                p.Description, err = proc.replaceRefs(p.Description, elems, len(elems))
6✔
276
                if err != nil {
6✔
277
                        return err
×
278
                }
×
279
        }
280

281
        for _, o := range f.Overloads {
24✔
282
                err := proc.processLinksMethod(o, elems)
8✔
283
                if err != nil {
8✔
284
                        return err
×
285
                }
×
286
        }
287

288
        return nil
16✔
289
}
290

291
func (proc *Processor) replaceRefs(text string, elems []string, modElems int) (string, error) {
263✔
292
        indices, err := findLinks(text)
263✔
293
        if err != nil {
263✔
294
                return "", err
×
295
        }
×
296
        if len(indices) == 0 {
464✔
297
                return text, nil
201✔
298
        }
201✔
299
        for i := len(indices) - 2; i >= 0; i -= 2 {
182✔
300
                start, end := indices[i], indices[i+1]
120✔
301
                link := text[start+1 : end-1]
120✔
302

120✔
303
                content, ok, err := proc.refToPlaceholder(link, elems, modElems)
120✔
304
                if err != nil {
120✔
305
                        return "", err
×
306
                }
×
307
                if !ok {
120✔
308
                        continue
×
309
                }
310
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
120✔
311
        }
312
        return text, nil
62✔
313
}
314

315
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
30✔
316
        indices, err := findLinks(text)
30✔
317
        if err != nil {
30✔
318
                return "", err
×
319
        }
×
320
        if len(indices) == 0 {
46✔
321
                return text, nil
16✔
322
        }
16✔
323
        for i := len(indices) - 2; i >= 0; i -= 2 {
126✔
324
                start, end := indices[i], indices[i+1]
112✔
325
                link := text[start+1 : end-1]
112✔
326

112✔
327
                entry, linkText, parts, ok, err := proc.placeholderToLink(link, elems, modElems, proc.Config.ShortLinks)
112✔
328
                if err != nil {
112✔
329
                        return "", err
×
330
                }
×
331
                if !ok {
112✔
332
                        continue
×
333
                }
334

335
                var basePath string
112✔
336
                if entry.IsSection {
190✔
337
                        basePath = path.Join(parts[:len(parts)-1]...)
78✔
338
                } else {
112✔
339
                        basePath = path.Join(parts...)
34✔
340
                }
34✔
341

342
                pathStr, err := proc.Formatter.ToLinkPath(basePath, entry.Kind)
112✔
343
                if err != nil {
112✔
344
                        return "", err
×
345
                }
×
346
                if entry.IsSection {
190✔
347
                        pathStr += parts[len(parts)-1]
78✔
348
                }
78✔
349
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
112✔
350
        }
351
        return text, nil
14✔
352
}
353

354
func (proc *Processor) placeholderToLink(link string, elems []string, modElems int, shorten bool) (entry *elemPath, text string, parts []string, ok bool, err error) {
112✔
355
        linkParts := strings.SplitN(link, " ", 2)
112✔
356
        entry, text, parts, ok, err = proc.placeholderToRelLink(linkParts[0], elems, modElems)
112✔
357
        if err != nil {
112✔
358
                return
×
359
        }
×
360
        if !ok {
112✔
361
                return
×
362
        }
×
363
        if len(linkParts) > 1 {
113✔
364
                text = linkParts[1]
1✔
365
        } else {
112✔
366
                if shorten {
222✔
367
                        textParts := strings.Split(text, ".")
111✔
368
                        if entry.IsSection {
188✔
369
                                text = strings.Join(textParts[len(textParts)-2:], ".")
77✔
370
                        } else {
111✔
371
                                text = textParts[len(textParts)-1]
34✔
372
                        }
34✔
373
                }
374
                text = fmt.Sprintf("`%s`", text)
111✔
375
        }
376
        return
112✔
377
}
378

379
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool, error) {
112✔
380
        elemPath, ok := proc.linkTargets[link]
112✔
381
        if !ok {
112✔
382
                err := proc.warnOrError("Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
383
                return nil, "", nil, false, err
×
384
        }
×
385
        skip := 0
112✔
386
        for range modElems {
254✔
387
                if skip >= len(elemPath.Elements) {
143✔
388
                        break
1✔
389
                }
390
                if elemPath.Elements[skip] == elems[skip] {
280✔
391
                        skip++
139✔
392
                } else {
141✔
393
                        break
2✔
394
                }
395
        }
396
        fullPath := []string{}
112✔
397
        for range modElems - skip {
115✔
398
                fullPath = append(fullPath, "..")
3✔
399
        }
3✔
400
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
112✔
401
        if len(fullPath) == 0 {
114✔
402
                fullPath = []string{"."}
2✔
403
        }
2✔
404
        return &elemPath, link, fullPath, true, nil
112✔
405
}
406

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

120✔
410
        var placeholder string
120✔
411
        var ok bool
120✔
412
        var err error
120✔
413
        if strings.HasPrefix(link, ".") {
218✔
414
                placeholder, ok, err = proc.refToPlaceholderRel(linkParts[0], elems, modElems)
98✔
415
        } else {
120✔
416
                placeholder, ok, err = proc.refToPlaceholderAbs(linkParts[0], elems)
22✔
417
        }
22✔
418
        if err != nil {
120✔
419
                return "", false, err
×
420
        }
×
421
        if !ok {
120✔
422
                return "", false, nil
×
423
        }
×
424

425
        if len(linkParts) > 1 {
121✔
426
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true, nil
1✔
427
        } else {
120✔
428
                return placeholder, true, nil
119✔
429
        }
119✔
430
}
431

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

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

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

467
func findLinks(text string) ([]int, error) {
294✔
468
        re, err := regexp.Compile(regexString)
294✔
469
        if err != nil {
294✔
470
                return nil, err
×
471
        }
×
472
        links := []int{}
294✔
473
        results := re.FindAllStringSubmatchIndex(text, -1)
294✔
474
        for _, r := range results {
679✔
475
                if r[6] >= 0 {
644✔
476
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
284✔
477
                                continue
25✔
478
                        }
479
                        links = append(links, r[6], r[7])
234✔
480
                }
481
        }
482

483
        return links, nil
294✔
484
}
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