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

mlange-42 / modo / 12845272312

18 Jan 2025 03:31PM CUT coverage: 59.033%. Remained the same
12845272312

push

github

web-flow
Fix README, update CHANGELOG (#65)

794 of 1345 relevant lines covered (59.03%)

7.46 hits per line

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

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

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

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

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

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

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

77
        return nil
5✔
78
}
79

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

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

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

129
        return nil
3✔
130
}
131

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

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

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

172
        return nil
2✔
173
}
174

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

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

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

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

220
        return nil
4✔
221
}
222

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

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

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

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

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

285
        return nil
4✔
286
}
287

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

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

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

8✔
321
                entry, linkText, parts, ok := proc.placeholderToLink(link, elems, modElems, proc.ShortLinks)
8✔
322
                if !ok {
8✔
323
                        continue
×
324
                }
325

326
                var basePath string
8✔
327
                if entry.IsSection {
10✔
328
                        basePath = path.Join(parts[:len(parts)-1]...)
2✔
329
                } else {
8✔
330
                        basePath = path.Join(parts...)
6✔
331
                }
6✔
332

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

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

367
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool) {
8✔
368
        elemPath, ok := proc.linkTargets[link]
8✔
369
        if !ok {
8✔
370
                log.Printf("WARNING: Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
371
                return nil, "", nil, false
×
372
        }
×
373
        skip := 0
8✔
374
        for range modElems {
22✔
375
                if len(elemPath.Elements) <= skip {
15✔
376
                        break
1✔
377
                }
378
                if elemPath.Elements[skip] == elems[skip] {
24✔
379
                        skip++
11✔
380
                } else {
13✔
381
                        break
2✔
382
                }
383
        }
384
        fullPath := []string{}
8✔
385
        for range modElems - skip {
11✔
386
                fullPath = append(fullPath, "..")
3✔
387
        }
3✔
388
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
8✔
389
        if len(fullPath) == 0 {
8✔
390
                fullPath = append(fullPath, ".")
×
391
        }
×
392

393
        return &elemPath, link, fullPath, true
8✔
394
}
395

396
func (proc *Processor) refToPlaceholder(link string, elems []string, modElems int) (string, bool) {
8✔
397
        linkParts := strings.SplitN(link, " ", 2)
8✔
398

8✔
399
        var placeholder string
8✔
400
        var ok bool
8✔
401
        if strings.HasPrefix(link, ".") {
14✔
402
                placeholder, ok = proc.refToPlaceholderRel(linkParts[0], elems, modElems)
6✔
403
        } else {
8✔
404
                placeholder, ok = proc.refToPlaceholderAbs(linkParts[0], elems)
2✔
405
        }
2✔
406
        if !ok {
8✔
407
                return "", false
×
408
        }
×
409
        if len(linkParts) > 1 {
9✔
410
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true
1✔
411
        } else {
8✔
412
                return placeholder, true
7✔
413
        }
7✔
414
}
415

416
func (proc *Processor) refToPlaceholderRel(link string, elems []string, modElems int) (string, bool) {
6✔
417
        dots := 0
6✔
418
        for strings.HasPrefix(link[dots:], ".") {
13✔
419
                dots++
7✔
420
        }
7✔
421
        if dots > modElems {
6✔
422
                log.Printf("WARNING: Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
423
                return "", false
×
424
        }
×
425
        linkText := link[dots:]
6✔
426
        subElems := elems[:modElems-(dots-1)]
6✔
427
        var fullLink string
6✔
428
        if len(subElems) == 0 {
6✔
429
                fullLink = linkText
×
430
        } else {
6✔
431
                fullLink = strings.Join(subElems, ".") + "." + linkText
6✔
432
        }
6✔
433

434
        placeholder, ok := proc.linkExports[fullLink]
6✔
435
        if !ok {
6✔
436
                log.Printf("WARNING: Can't resolve cross ref (rel) '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
×
437
                return "", false
×
438
        }
×
439
        return placeholder, true
6✔
440
}
441

442
func (proc *Processor) refToPlaceholderAbs(link string, elems []string) (string, bool) {
2✔
443
        placeholder, ok := proc.linkExports[link]
2✔
444
        if !ok {
2✔
445
                log.Printf("WARNING: Can't resolve cross ref (abs) '%s' in %s", link, strings.Join(elems, "."))
×
446
                return "", false
×
447
        }
×
448
        return placeholder, true
2✔
449
}
450

451
func findLinks(text string) ([]int, error) {
109✔
452
        re, err := regexp.Compile(regexString)
109✔
453
        if err != nil {
109✔
454
                return nil, err
×
455
        }
×
456
        links := []int{}
109✔
457
        results := re.FindAllStringSubmatchIndex(text, -1)
109✔
458
        for _, r := range results {
178✔
459
                if r[6] >= 0 {
100✔
460
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
44✔
461
                                continue
13✔
462
                        }
463
                        links = append(links, r[6], r[7])
18✔
464
                }
465
        }
466

467
        return links, nil
109✔
468
}
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