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

mlange-42 / modo / 12821068519

17 Jan 2025 01:47AM CUT coverage: 36.563%. Remained the same
12821068519

Pull #53

github

web-flow
Merge 0bfc5ef9a into bc43036f2
Pull Request #53: Add CLI help to README

468 of 1280 relevant lines covered (36.56%)

2.63 hits per line

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

16.76
/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) processLinksPackage(p *Package, elems []string) error {
×
33
        newElems := AppendNew(elems, p.GetName())
×
34

×
35
        var err error
×
36
        p.Summary, err = proc.replaceRefs(p.Summary, newElems, len(newElems))
×
37
        if err != nil {
×
38
                return err
×
39
        }
×
40
        p.Description, err = proc.replaceRefs(p.Description, newElems, len(newElems))
×
41
        if err != nil {
×
42
                return err
×
43
        }
×
44

45
        for _, pkg := range p.Packages {
×
46
                proc.processLinksPackage(pkg, newElems)
×
47
        }
×
48
        for _, mod := range p.Modules {
×
49
                proc.processLinksModule(mod, newElems)
×
50
        }
×
51

52
        for _, f := range p.Functions {
×
53
                err := proc.processLinksFunction(f, newElems)
×
54
                if err != nil {
×
55
                        return err
×
56
                }
×
57
        }
58
        for _, s := range p.Structs {
×
59
                err := proc.processLinksStruct(s, newElems)
×
60
                if err != nil {
×
61
                        return err
×
62
                }
×
63
        }
64
        for _, tr := range p.Traits {
×
65
                err := proc.processLinksTrait(tr, newElems)
×
66
                if err != nil {
×
67
                        return err
×
68
                }
×
69
        }
70

71
        return nil
×
72
}
73

74
func (proc *Processor) processLinksModule(m *Module, elems []string) error {
×
75
        newElems := AppendNew(elems, m.GetName())
×
76

×
77
        var err error
×
78
        m.Summary, err = proc.replaceRefs(m.Summary, newElems, len(newElems))
×
79
        if err != nil {
×
80
                return err
×
81
        }
×
82
        m.Description, err = proc.replaceRefs(m.Description, newElems, len(newElems))
×
83
        if err != nil {
×
84
                return err
×
85
        }
×
86

87
        for _, a := range m.Aliases {
×
88
                err := proc.processLinksAlias(a, newElems)
×
89
                if err != nil {
×
90
                        return err
×
91
                }
×
92
        }
93
        for _, f := range m.Functions {
×
94
                err := proc.processLinksFunction(f, newElems)
×
95
                if err != nil {
×
96
                        return err
×
97
                }
×
98
        }
99
        for _, s := range m.Structs {
×
100
                err := proc.processLinksStruct(s, newElems)
×
101
                if err != nil {
×
102
                        return err
×
103
                }
×
104
        }
105
        for _, tr := range m.Traits {
×
106
                err := proc.processLinksTrait(tr, newElems)
×
107
                if err != nil {
×
108
                        return err
×
109
                }
×
110
        }
111

112
        return nil
×
113
}
114

115
func (proc *Processor) processLinksStruct(s *Struct, elems []string) error {
×
116
        newElems := AppendNew(elems, s.GetName())
×
117

×
118
        var err error
×
119
        s.Summary, err = proc.replaceRefs(s.Summary, newElems, len(elems))
×
120
        if err != nil {
×
121
                return err
×
122
        }
×
123
        s.Description, err = proc.replaceRefs(s.Description, newElems, len(elems))
×
124
        if err != nil {
×
125
                return err
×
126
        }
×
127

128
        for _, a := range s.Aliases {
×
129
                a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
×
130
                if err != nil {
×
131
                        return err
×
132
                }
×
133
        }
134
        for _, p := range s.Parameters {
×
135
                p.Description, err = proc.replaceRefs(p.Description, newElems, len(elems))
×
136
                if err != nil {
×
137
                        return err
×
138
                }
×
139
        }
140
        for _, f := range s.Fields {
×
141
                f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
×
142
                if err != nil {
×
143
                        return err
×
144
                }
×
145
                f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
×
146
                if err != nil {
×
147
                        return err
×
148
                }
×
149
        }
150
        for _, f := range s.Functions {
×
151
                if err := proc.processLinksMethod(f, elems); err != nil {
×
152
                        return err
×
153
                }
×
154
        }
155

156
        return nil
×
157
}
158

159
func (proc *Processor) processLinksTrait(tr *Trait, elems []string) error {
×
160
        newElems := AppendNew(elems, tr.GetName())
×
161

×
162
        var err error
×
163
        tr.Summary, err = proc.replaceRefs(tr.Summary, newElems, len(elems))
×
164
        if err != nil {
×
165
                return err
×
166
        }
×
167
        tr.Description, err = proc.replaceRefs(tr.Description, newElems, len(elems))
×
168
        if err != nil {
×
169
                return err
×
170
        }
×
171

172
        // TODO: add when traits support parameters
173
        /*for _, p := range tr.Parameters {
174
                p.Description, err = replaceLinks(p.Description, newElems, len(elems), lookup, t)
175
                if err != nil {
176
                        return err
177
                }
178
        }*/
179
        for _, f := range tr.Fields {
×
180
                f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
×
181
                if err != nil {
×
182
                        return err
×
183
                }
×
184
                f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
×
185
                if err != nil {
×
186
                        return err
×
187
                }
×
188
        }
189
        for _, f := range tr.Functions {
×
190
                if err := proc.processLinksMethod(f, elems); err != nil {
×
191
                        return err
×
192
                }
×
193
        }
194

195
        return nil
×
196
}
197

198
func (proc *Processor) processLinksFunction(f *Function, elems []string) error {
×
199
        newElems := AppendNew(elems, f.GetName())
×
200

×
201
        var err error
×
202
        f.Summary, err = proc.replaceRefs(f.Summary, newElems, len(elems))
×
203
        if err != nil {
×
204
                return err
×
205
        }
×
206
        f.Description, err = proc.replaceRefs(f.Description, newElems, len(elems))
×
207
        if err != nil {
×
208
                return err
×
209
        }
×
210
        f.ReturnsDoc, err = proc.replaceRefs(f.ReturnsDoc, newElems, len(elems))
×
211
        if err != nil {
×
212
                return err
×
213
        }
×
214
        f.RaisesDoc, err = proc.replaceRefs(f.RaisesDoc, newElems, len(elems))
×
215
        if err != nil {
×
216
                return err
×
217
        }
×
218

219
        for _, a := range f.Args {
×
220
                a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
×
221
                if err != nil {
×
222
                        return err
×
223
                }
×
224
        }
225
        for _, p := range f.Parameters {
×
226
                p.Description, err = proc.replaceRefs(p.Description, newElems, len(elems))
×
227
                if err != nil {
×
228
                        return err
×
229
                }
×
230
        }
231

232
        for _, o := range f.Overloads {
×
233
                err := proc.processLinksFunction(o, elems)
×
234
                if err != nil {
×
235
                        return err
×
236
                }
×
237
        }
238

239
        return nil
×
240
}
241

242
func (proc *Processor) processLinksAlias(a *Alias, elems []string) error {
×
243
        newElems := AppendNew(elems, a.GetName())
×
244

×
245
        var err error
×
246
        a.Summary, err = proc.replaceRefs(a.Summary, newElems, len(elems))
×
247
        if err != nil {
×
248
                return err
×
249
        }
×
250
        a.Description, err = proc.replaceRefs(a.Description, newElems, len(elems))
×
251
        if err != nil {
×
252
                return err
×
253
        }
×
254
        return nil
×
255
}
256

257
func (proc *Processor) processLinksMethod(f *Function, elems []string) error {
×
258
        var err error
×
259
        f.Summary, err = proc.replaceRefs(f.Summary, elems, len(elems))
×
260
        if err != nil {
×
261
                return err
×
262
        }
×
263
        f.Description, err = proc.replaceRefs(f.Description, elems, len(elems))
×
264
        if err != nil {
×
265
                return err
×
266
        }
×
267
        f.ReturnsDoc, err = proc.replaceRefs(f.ReturnsDoc, elems, len(elems))
×
268
        if err != nil {
×
269
                return err
×
270
        }
×
271
        f.RaisesDoc, err = proc.replaceRefs(f.RaisesDoc, elems, len(elems))
×
272
        if err != nil {
×
273
                return err
×
274
        }
×
275

276
        for _, a := range f.Args {
×
277
                a.Description, err = proc.replaceRefs(a.Description, elems, len(elems))
×
278
                if err != nil {
×
279
                        return err
×
280
                }
×
281
        }
282
        for _, p := range f.Parameters {
×
283
                p.Description, err = proc.replaceRefs(p.Description, elems, len(elems))
×
284
                if err != nil {
×
285
                        return err
×
286
                }
×
287
        }
288

289
        for _, o := range f.Overloads {
×
290
                err := proc.processLinksMethod(o, elems)
×
291
                if err != nil {
×
292
                        return err
×
293
                }
×
294
        }
295

296
        return nil
×
297
}
298

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

5✔
311
                content, ok := proc.refToPlaceholder(link, elems, modElems)
5✔
312
                if !ok {
10✔
313
                        continue
5✔
314
                }
315
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
×
316
        }
317
        return text, nil
1✔
318
}
319

320
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
×
321
        indices, err := findLinks(text)
×
322
        if err != nil {
×
323
                return "", err
×
324
        }
×
325
        if len(indices) == 0 {
×
326
                return text, nil
×
327
        }
×
328
        for i := len(indices) - 2; i >= 0; i -= 2 {
×
329
                start, end := indices[i], indices[i+1]
×
330
                link := text[start+1 : end-1]
×
331

×
332
                entry, linkText, parts, ok := proc.placeholderToLink(link, elems, modElems, proc.ShortLinks)
×
333
                if !ok {
×
334
                        continue
×
335
                }
336

337
                var basePath string
×
338
                if entry.IsSection {
×
339
                        basePath = path.Join(parts[:len(parts)-1]...)
×
340
                } else {
×
341
                        basePath = path.Join(parts...)
×
342
                }
×
343

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

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

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

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

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

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

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

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