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

mlange-42 / modo / 12916744138

22 Jan 2025 08:44PM CUT coverage: 61.572%. Remained the same
12916744138

push

github

web-flow
Package for commands, extend CLI help (#100)

* move commands to package
* improve file structure
* remove commented out code
* add guide link to CLI help
* tweak user guide

987 of 1603 relevant lines covered (61.57%)

29.41 hits per line

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

79.64
/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
var re *regexp.Regexp
13

14
func init() {
1✔
15
        var err error
1✔
16
        re, err = regexp.Compile(regexString)
1✔
17
        if err != nil {
1✔
18
                panic(err)
×
19
        }
20
}
21

22
func (proc *Processor) processLinks(docs *Docs) error {
6✔
23
        return proc.walkDocs(docs, proc.replaceRefs, func(elem Named) string {
51✔
24
                return elem.GetName()
45✔
25
        })
45✔
26
}
27

28
func (proc *Processor) replaceRefs(text string, elems []string, modElems int) (string, error) {
295✔
29
        indices, err := findLinks(text)
295✔
30
        if err != nil {
295✔
31
                return "", err
×
32
        }
×
33
        if len(indices) == 0 {
528✔
34
                return text, nil
233✔
35
        }
233✔
36
        for i := len(indices) - 2; i >= 0; i -= 2 {
182✔
37
                start, end := indices[i], indices[i+1]
120✔
38
                link := text[start+1 : end-1]
120✔
39

120✔
40
                content, ok, err := proc.refToPlaceholder(link, elems, modElems)
120✔
41
                if err != nil {
120✔
42
                        return "", err
×
43
                }
×
44
                if !ok {
120✔
45
                        continue
×
46
                }
47
                text = fmt.Sprintf("%s[%s]%s", text[:start], content, text[end:])
120✔
48
        }
49
        return text, nil
62✔
50
}
51

52
func (proc *Processor) ReplacePlaceholders(text string, elems []string, modElems int) (string, error) {
34✔
53
        indices, err := findLinks(text)
34✔
54
        if err != nil {
34✔
55
                return "", err
×
56
        }
×
57
        if len(indices) == 0 {
54✔
58
                return text, nil
20✔
59
        }
20✔
60
        for i := len(indices) - 2; i >= 0; i -= 2 {
126✔
61
                start, end := indices[i], indices[i+1]
112✔
62
                link := text[start+1 : end-1]
112✔
63

112✔
64
                entry, linkText, parts, ok, err := proc.placeholderToLink(link, elems, modElems, proc.Config.ShortLinks)
112✔
65
                if err != nil {
112✔
66
                        return "", err
×
67
                }
×
68
                if !ok {
112✔
69
                        continue
×
70
                }
71

72
                var basePath string
112✔
73
                if entry.IsSection {
190✔
74
                        basePath = path.Join(parts[:len(parts)-1]...)
78✔
75
                } else {
112✔
76
                        basePath = path.Join(parts...)
34✔
77
                }
34✔
78

79
                pathStr, err := proc.Formatter.ToLinkPath(basePath, entry.Kind)
112✔
80
                if err != nil {
112✔
81
                        return "", err
×
82
                }
×
83
                if entry.IsSection {
190✔
84
                        pathStr += parts[len(parts)-1]
78✔
85
                }
78✔
86
                text = fmt.Sprintf("%s[%s](%s)%s", text[:start], linkText, pathStr, text[end:])
112✔
87
        }
88
        return text, nil
14✔
89
}
90

91
func (proc *Processor) placeholderToLink(link string, elems []string, modElems int, shorten bool) (entry *elemPath, text string, parts []string, ok bool, err error) {
112✔
92
        linkParts := strings.SplitN(link, " ", 2)
112✔
93
        entry, text, parts, ok, err = proc.placeholderToRelLink(linkParts[0], elems, modElems)
112✔
94
        if err != nil {
112✔
95
                return
×
96
        }
×
97
        if !ok {
112✔
98
                return
×
99
        }
×
100
        if len(linkParts) > 1 {
113✔
101
                text = linkParts[1]
1✔
102
        } else {
112✔
103
                if shorten {
222✔
104
                        textParts := strings.Split(text, ".")
111✔
105
                        if entry.IsSection {
188✔
106
                                text = strings.Join(textParts[len(textParts)-2:], ".")
77✔
107
                        } else {
111✔
108
                                text = textParts[len(textParts)-1]
34✔
109
                        }
34✔
110
                }
111
                text = fmt.Sprintf("`%s`", text)
111✔
112
        }
113
        return
112✔
114
}
115

116
func (proc *Processor) placeholderToRelLink(link string, elems []string, modElems int) (*elemPath, string, []string, bool, error) {
112✔
117
        elemPath, ok := proc.linkTargets[link]
112✔
118
        if !ok {
112✔
119
                err := proc.warnOrError("Can't resolve cross ref placeholder '%s' in %s", link, strings.Join(elems, "."))
×
120
                return nil, "", nil, false, err
×
121
        }
×
122
        skip := 0
112✔
123
        for range modElems {
254✔
124
                if skip >= len(elemPath.Elements) {
143✔
125
                        break
1✔
126
                }
127
                if elemPath.Elements[skip] == elems[skip] {
280✔
128
                        skip++
139✔
129
                } else {
141✔
130
                        break
2✔
131
                }
132
        }
133
        fullPath := []string{}
112✔
134
        for range modElems - skip {
115✔
135
                fullPath = append(fullPath, "..")
3✔
136
        }
3✔
137
        fullPath = append(fullPath, elemPath.Elements[skip:]...)
112✔
138
        if len(fullPath) == 0 {
114✔
139
                fullPath = []string{"."}
2✔
140
        }
2✔
141
        return &elemPath, link, fullPath, true, nil
112✔
142
}
143

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

120✔
147
        var placeholder string
120✔
148
        var ok bool
120✔
149
        var err error
120✔
150
        if strings.HasPrefix(link, ".") {
218✔
151
                placeholder, ok, err = proc.refToPlaceholderRel(linkParts[0], elems, modElems)
98✔
152
        } else {
120✔
153
                placeholder, ok, err = proc.refToPlaceholderAbs(linkParts[0], elems)
22✔
154
        }
22✔
155
        if err != nil {
120✔
156
                return "", false, err
×
157
        }
×
158
        if !ok {
120✔
159
                return "", false, nil
×
160
        }
×
161

162
        if len(linkParts) > 1 {
121✔
163
                return fmt.Sprintf("%s %s", placeholder, linkParts[1]), true, nil
1✔
164
        } else {
120✔
165
                return placeholder, true, nil
119✔
166
        }
119✔
167
}
168

169
func (proc *Processor) refToPlaceholderRel(link string, elems []string, modElems int) (string, bool, error) {
98✔
170
        dots := 0
98✔
171
        for strings.HasPrefix(link[dots:], ".") {
201✔
172
                dots++
103✔
173
        }
103✔
174
        if dots > modElems {
98✔
175
                err := proc.warnOrError("Too many leading dots in cross ref '%s' in %s", link, strings.Join(elems, "."))
×
176
                return "", false, err
×
177
        }
×
178
        linkText := link[dots:]
98✔
179
        subElems := elems[:modElems-(dots-1)]
98✔
180
        var fullLink string
98✔
181
        if len(subElems) == 0 {
98✔
182
                fullLink = linkText
×
183
        } else {
98✔
184
                fullLink = strings.Join(subElems, ".") + "." + linkText
98✔
185
        }
98✔
186

187
        placeholder, ok := proc.linkExports[fullLink]
98✔
188
        if !ok {
98✔
189
                err := proc.warnOrError("Can't resolve cross ref (rel) '%s' (%s) in %s", link, fullLink, strings.Join(elems, "."))
×
190
                return "", false, err
×
191
        }
×
192
        return placeholder, true, nil
98✔
193
}
194

195
func (proc *Processor) refToPlaceholderAbs(link string, elems []string) (string, bool, error) {
22✔
196
        placeholder, ok := proc.linkExports[link]
22✔
197
        if !ok {
22✔
198
                err := proc.warnOrError("Can't resolve cross ref (abs) '%s' in %s", link, strings.Join(elems, "."))
×
199
                return "", false, err
×
200
        }
×
201
        return placeholder, true, nil
22✔
202
}
203

204
func findLinks(text string) ([]int, error) {
330✔
205
        links := []int{}
330✔
206
        results := re.FindAllStringSubmatchIndex(text, -1)
330✔
207
        for _, r := range results {
743✔
208
                if r[6] >= 0 {
676✔
209
                        if len(text) > r[7] && string(text[r[7]]) == "(" {
292✔
210
                                continue
29✔
211
                        }
212
                        links = append(links, r[6], r[7])
234✔
213
                }
214
        }
215

216
        return links, nil
330✔
217
}
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