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

mlange-42 / modo / 13146653622

04 Feb 2025 11:14PM CUT coverage: 72.623% (+0.03%) from 72.594%
13146653622

push

github

web-flow
Implement `from .mod import X as Y` re-exports (#189)

124 of 169 new or added lines in 6 files covered. (73.37%)

1 existing line in 1 file now uncovered.

1650 of 2272 relevant lines covered (72.62%)

26.84 hits per line

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

82.2
/document/exports.go
1
package document
2

3
import (
4
        "bufio"
5
        "fmt"
6
        "strings"
7
)
8

9
const exportsMarker = "Exports:"
10
const exportsPrefix = "- "
11

12
type packageExport struct {
13
        Short    []string
14
        Exported []string
15
        Renamed  string
16
        Long     []string
17
}
18

19
// Parses and collects project re-exports, recursively.
20
func (proc *Processor) collectExports(p *Package, elems []string) (bool, error) {
12✔
21
        proc.renameExports = map[string]string{}
12✔
22
        anyExports := false
12✔
23

12✔
24
        newElems := appendNew(elems, p.Name)
12✔
25
        for _, pkg := range p.Packages {
16✔
26
                anyHere, err := proc.collectExports(pkg, newElems)
4✔
27
                if err != nil {
4✔
28
                        return anyExports, err
×
29
                }
×
30
                if anyHere {
8✔
31
                        anyExports = true
4✔
32
                }
4✔
33
        }
34

35
        if proc.Config.UseExports {
21✔
36
                var anyHere bool
9✔
37
                var err error
9✔
38
                p.exports, p.Description, anyHere, err = proc.parseExports(p.Description, newElems, true)
9✔
39
                if err != nil {
9✔
NEW
40
                        return anyExports, err
×
NEW
41
                }
×
42
                if anyHere {
18✔
43
                        anyExports = true
9✔
44
                }
9✔
45
                for _, ex := range p.exports {
41✔
46
                        longPath := strings.Join(ex.Long, ".")
32✔
47
                        if _, ok := proc.allPaths[longPath]; !ok {
32✔
NEW
48
                                return anyExports, fmt.Errorf("unresolved package re-export '%s' in %s", longPath, strings.Join(newElems, "."))
×
NEW
49
                        }
×
50
                        if ex.Renamed != ex.Exported[len(ex.Exported)-1] {
40✔
51
                                exported := strings.Join(ex.Exported, ".")
8✔
52
                                proc.renameExports[exported] = ex.Renamed
8✔
53
                        }
8✔
54
                }
55
                return anyExports, nil
9✔
56
        }
57

58
        p.exports = make([]*packageExport, 0, len(p.Packages)+len(p.Modules))
3✔
59
        for _, pkg := range p.Packages {
3✔
NEW
60
                p.exports = append(p.exports, &packageExport{
×
NEW
61
                        Short:    []string{pkg.Name},
×
NEW
62
                        Exported: appendNew(newElems, pkg.Name),
×
NEW
63
                        Renamed:  pkg.Name,
×
NEW
64
                        Long:     appendNew(newElems, pkg.Name),
×
NEW
65
                })
×
UNCOV
66
        }
×
67
        for _, mod := range p.Modules {
6✔
68
                p.exports = append(p.exports, &packageExport{
3✔
69
                        Short:    []string{mod.Name},
3✔
70
                        Exported: appendNew(newElems, mod.Name),
3✔
71
                        Renamed:  mod.Name,
3✔
72
                        Long:     appendNew(newElems, mod.Name),
3✔
73
                })
3✔
74
        }
3✔
75

76
        return anyExports, nil
3✔
77
}
78

79
func (proc *Processor) parseExports(pkgDocs string, basePath []string, remove bool) ([]*packageExport, string, bool, error) {
10✔
80
        scanner := bufio.NewScanner(strings.NewReader(pkgDocs))
10✔
81

10✔
82
        outText := strings.Builder{}
10✔
83
        exports := []*packageExport{}
10✔
84
        anyExports := false
10✔
85
        isExport := false
10✔
86
        fenced3 := false
10✔
87
        fenced4 := false
10✔
88

10✔
89
        exportIndex := 0
10✔
90
        for scanner.Scan() {
116✔
91
                origLine := scanner.Text()
106✔
92
                line := strings.TrimSpace(origLine)
106✔
93

106✔
94
                fenced := false
106✔
95
                if strings.HasPrefix(origLine, codeFence3) {
108✔
96
                        fenced3 = !fenced3
2✔
97
                        fenced = true
2✔
98
                }
2✔
99
                if strings.HasPrefix(origLine, codeFence4) {
106✔
100
                        fenced4 = !fenced4
×
101
                        fenced = true
×
102
                }
×
103
                if fenced || fenced3 || fenced4 {
112✔
104
                        isExport = false
6✔
105
                        outText.WriteString(origLine)
6✔
106
                        outText.WriteRune('\n')
6✔
107
                        continue
6✔
108
                }
109

110
                if isExport {
139✔
111
                        if exportIndex == 0 && line == "" {
40✔
112
                                continue
1✔
113
                        }
114
                        if !strings.HasPrefix(line, exportsPrefix) {
40✔
115
                                outText.WriteString(origLine)
2✔
116
                                outText.WriteRune('\n')
2✔
117
                                isExport = false
2✔
118
                                continue
2✔
119
                        }
120
                        exportsAs := strings.Split(line[len(exportsPrefix):], " ")
36✔
121
                        short := exportsAs[0]
36✔
122
                        partsShort := strings.Split(short, ".")
36✔
123
                        renamed := partsShort[len(partsShort)-1]
36✔
124
                        if len(exportsAs) == 3 && exportsAs[1] == "as" {
45✔
125
                                renamed = exportsAs[2]
9✔
126
                        } else if len(exportsAs) != 1 {
36✔
NEW
127
                                if err := proc.warnOrError("invalid syntax in package re-export '%s' in %s", line[len(exportsPrefix):], strings.Join(basePath, ".")); err != nil {
×
NEW
128
                                        return nil, "", false, err
×
NEW
129
                                }
×
130
                        }
131
                        exports = append(exports, &packageExport{
36✔
132
                                Short:    partsShort,
36✔
133
                                Exported: appendNew(basePath, partsShort[len(partsShort)-1]),
36✔
134
                                Renamed:  renamed,
36✔
135
                                Long:     appendNew(basePath, partsShort...)})
36✔
136
                        anyExports = true
36✔
137
                        exportIndex++
36✔
138
                } else {
61✔
139
                        if line == exportsMarker {
72✔
140
                                isExport = true
11✔
141
                                exportIndex = 0
11✔
142
                                continue
11✔
143
                        }
144
                        outText.WriteString(origLine)
50✔
145
                        outText.WriteRune('\n')
50✔
146
                }
147
        }
148
        if err := scanner.Err(); err != nil {
10✔
149
                panic(err)
×
150
        }
151
        if remove {
20✔
152
                return exports, strings.TrimSuffix(outText.String(), "\n"), anyExports, nil
10✔
153
        }
10✔
NEW
154
        return exports, pkgDocs, anyExports, nil
×
155
}
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