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

mlange-42 / modo / 13162005183

05 Feb 2025 04:28PM CUT coverage: 72.707%. Remained the same
13162005183

Pull #206

github

web-flow
Merge 323cbe4df into 30d34556d
Pull Request #206: Fix souce links for packages with upper-case characters

1 of 2 new or added lines in 1 file covered. (50.0%)

1649 of 2268 relevant lines covered (72.71%)

26.89 hits per line

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

59.05
/internal/format/mdbook.go
1
package format
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io"
7
        "io/fs"
8
        "os"
9
        "path"
10
        "strings"
11
        "text/template"
12

13
        "github.com/mlange-42/modo/assets"
14
        "github.com/mlange-42/modo/internal/document"
15
)
16

17
type MdBook struct{}
18

19
type mdBookConfig struct {
20
        Title string
21
}
22

23
func (f *MdBook) Accepts(files []string) error {
2✔
24
        if len(files) > 1 {
3✔
25
                return fmt.Errorf("mdBook formatter can process only a single JSON file, but %d is given", len(files))
1✔
26
        }
1✔
27
        if len(files) == 0 || files[0] == "" {
1✔
28
                return nil
×
29
        }
×
30
        if s, err := os.Stat(files[0]); err == nil {
2✔
31
                if s.IsDir() {
2✔
32
                        return fmt.Errorf("mdBook formatter can process only a single JSON file, but directory '%s' is given", files[0])
1✔
33
                }
1✔
34
        } else {
×
35
                return err
×
36
        }
×
37
        return nil
×
38
}
39

40
func (f *MdBook) ProcessMarkdown(element any, text string, proc *document.Processor) (string, error) {
×
41
        return text, nil
×
42
}
×
43

44
func (f *MdBook) WriteAuxiliary(p *document.Package, dir string, proc *document.Processor) error {
×
45
        if err := f.writeSummary(p, dir, proc); err != nil {
×
46
                return err
×
47
        }
×
48
        return nil
×
49
}
50

51
func (f *MdBook) ToFilePath(p string, kind string) string {
10✔
52
        if kind == "package" || kind == "module" {
17✔
53
                return path.Join(p, "_index.md")
7✔
54
        }
7✔
55
        if len(p) == 0 {
3✔
56
                return p
×
57
        }
×
58
        return p + ".md"
3✔
59
}
60

61
func (f *MdBook) ToLinkPath(p string, kind string) string {
7✔
62
        return f.ToFilePath(p, kind)
7✔
63
}
7✔
64

65
func (f *MdBook) Clean(out, _ string) error {
1✔
66
        dirs, err := os.ReadDir(out)
1✔
67
        if err != nil {
1✔
68
                return err
×
69
        }
×
70
        for _, info := range dirs {
4✔
71
                if !info.IsDir() {
4✔
72
                        continue
1✔
73
                }
74
                if info.Name() == "css" {
3✔
75
                        continue
1✔
76
                }
77
                if err := emptyDir(path.Join(out, info.Name())); err != nil {
1✔
78
                        return err
×
79
                }
×
80
        }
81

82
        return nil
1✔
83
}
84

85
type summary struct {
86
        Summary   string
87
        Packages  string
88
        Modules   string
89
        Structs   string
90
        Traits    string
91
        Functions string
92
}
93

94
func (f *MdBook) writeSummary(p *document.Package, dir string, proc *document.Processor) error {
×
95
        summary, err := f.renderSummary(p, proc)
×
96
        if err != nil {
×
97
                return err
×
98
        }
×
99
        summaryPath := path.Join(dir, p.GetFileName(), "SUMMARY.md")
×
100
        if proc.Config.DryRun {
×
101
                return nil
×
102
        }
×
103
        if err := os.WriteFile(summaryPath, []byte(summary), 0644); err != nil {
×
104
                return err
×
105
        }
×
106
        return nil
×
107
}
108

109
func (f *MdBook) renderSummary(p *document.Package, proc *document.Processor) (string, error) {
1✔
110
        s := summary{}
1✔
111

1✔
112
        pkgFile := f.ToLinkPath("", "package")
1✔
113
        s.Summary = fmt.Sprintf("[`%s`](%s)", p.GetName(), pkgFile)
1✔
114

1✔
115
        pkgs := strings.Builder{}
1✔
116
        for _, p := range p.Packages {
2✔
117
                if err := f.renderPackage(p, proc.Template, nil, &pkgs); err != nil {
1✔
118
                        return "", err
×
119
                }
×
120
        }
121
        s.Packages = pkgs.String()
1✔
122

1✔
123
        mods := strings.Builder{}
1✔
124
        for _, m := range p.Modules {
2✔
125
                if err := f.renderModule(m, nil, &mods); err != nil {
1✔
126
                        return "", err
×
127
                }
×
128
        }
129
        s.Modules = mods.String()
1✔
130

1✔
131
        elems := strings.Builder{}
1✔
132
        for _, elem := range p.Structs {
1✔
133
                if err := f.renderModuleMember(elem, "", 0, &elems); err != nil {
×
134
                        return "", err
×
135
                }
×
136
        }
137
        s.Structs = elems.String()
1✔
138
        elems = strings.Builder{}
1✔
139
        for _, elem := range p.Traits {
1✔
140
                if err := f.renderModuleMember(elem, "", 0, &elems); err != nil {
×
141
                        return "", err
×
142
                }
×
143
        }
144
        s.Traits = elems.String()
1✔
145
        elems = strings.Builder{}
1✔
146
        for _, elem := range p.Functions {
1✔
147
                if err := f.renderModuleMember(elem, "", 0, &elems); err != nil {
×
148
                        return "", err
×
149
                }
×
150
        }
151
        s.Functions = elems.String()
1✔
152

1✔
153
        b := strings.Builder{}
1✔
154
        if err := proc.Template.ExecuteTemplate(&b, "mdbook_summary.md", &s); err != nil {
1✔
155
                return "", err
×
156
        }
×
157

158
        return b.String(), nil
1✔
159
}
160

161
func (f *MdBook) renderPackage(pkg *document.Package, t *template.Template, linkPath []string, out *strings.Builder) error {
1✔
162
        newPath := append([]string{}, linkPath...)
1✔
163
        newPath = append(newPath, pkg.GetFileName())
1✔
164

1✔
165
        pkgFile := f.ToLinkPath(path.Join(newPath...), "package")
1✔
166
        fmt.Fprintf(out, "%-*s- [`%s`](%s))\n", 2*len(linkPath), "", pkg.GetName(), pkgFile)
1✔
167
        for _, p := range pkg.Packages {
1✔
168
                if err := f.renderPackage(p, t, newPath, out); err != nil {
×
169
                        return err
×
170
                }
×
171
        }
172
        for _, m := range pkg.Modules {
1✔
173
                if err := f.renderModule(m, newPath, out); err != nil {
×
174
                        return err
×
175
                }
×
176
        }
177

178
        pathStr := path.Join(newPath...)
1✔
179
        childDepth := 2*(len(newPath)-1) + 2
1✔
180
        for _, elem := range pkg.Structs {
1✔
181
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
×
182
                        return err
×
183
                }
×
184
        }
185
        for _, elem := range pkg.Traits {
1✔
186
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
×
187
                        return err
×
188
                }
×
189
        }
190
        for _, elem := range pkg.Functions {
1✔
191
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
×
192
                        return err
×
193
                }
×
194
        }
195

196
        return nil
1✔
197
}
198

199
func (f *MdBook) renderModule(mod *document.Module, linkPath []string, out *strings.Builder) error {
1✔
200
        newPath := append([]string{}, linkPath...)
1✔
201
        newPath = append(newPath, mod.GetFileName())
1✔
202

1✔
203
        pathStr := path.Join(newPath...)
1✔
204

1✔
205
        modFile := f.ToLinkPath(pathStr, "module")
1✔
206
        fmt.Fprintf(out, "%-*s- [`%s`](%s)\n", 2*(len(newPath)-1), "", mod.GetName(), modFile)
1✔
207

1✔
208
        childDepth := 2*(len(newPath)-1) + 2
1✔
209
        for _, elem := range mod.Structs {
2✔
210
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
1✔
211
                        return err
×
212
                }
×
213
        }
214
        for _, elem := range mod.Traits {
1✔
215
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
×
216
                        return err
×
217
                }
×
218
        }
219
        for _, elem := range mod.Functions {
1✔
220
                if err := f.renderModuleMember(elem, pathStr, childDepth, out); err != nil {
×
221
                        return err
×
222
                }
×
223
        }
224
        return nil
1✔
225
}
226

227
func (f *MdBook) renderModuleMember(mem document.Named, pathStr string, depth int, out io.Writer) error {
1✔
228
        memPath := f.ToLinkPath(path.Join(pathStr, mem.GetFileName(), ""), "")
1✔
229
        fmt.Fprintf(out, "%-*s- [`%s`](%s)\n", depth, "", mem.GetName(), memPath)
1✔
230
        return nil
1✔
231
}
1✔
232

233
func (f *MdBook) Input(in string, sources []document.PackageSource) string {
1✔
234
        file := sources[0].Name + ".json"
1✔
235
        return file
1✔
236
}
1✔
237

238
func (f *MdBook) Output(out string) string {
1✔
239
        return ""
1✔
240
}
1✔
241

242
func (f *MdBook) GitIgnore(in, out string, sources []document.PackageSource) []string {
1✔
243
        file := sources[0].Name + ".json"
1✔
244
        return []string{
1✔
245
                "# file generated by 'mojo doc'",
1✔
246
                fmt.Sprintf("/%s", file),
1✔
247
                "# files generated by Modo",
1✔
248
                fmt.Sprintf("/%s/", sources[0].Name),
1✔
249
                "# files generated by MdBook",
1✔
250
                fmt.Sprintf("/%s/", "public"),
1✔
251
                "# test file generated by Modo",
1✔
252
                "/test/",
1✔
253
        }
1✔
254
}
1✔
255

256
func (f *MdBook) CreateDirs(base, in, out string, sources []document.PackageSource, templ *template.Template) error {
1✔
257
        outDir := base
1✔
258
        testDir := path.Join(base, "test")
1✔
259
        if err := mkDirs(outDir); err != nil {
1✔
260
                return err
×
261
        }
×
262
        if err := mkDirs(testDir); err != nil {
1✔
263
                return err
×
264
        }
×
265
        return f.createInitialFiles(sources[0].Name, outDir, templ)
1✔
266
}
267

268
func (f *MdBook) createInitialFiles(title, docDir string, templ *template.Template) error {
1✔
269
        outFile := path.Join(docDir, "book.toml")
1✔
270
        exists, _, err := fileExists(outFile)
1✔
271
        if err != nil {
1✔
272
                return err
×
273
        }
×
274
        if exists {
1✔
275
                fmt.Printf("WARNING: MdBook config file %s already exists, skip creating\n", outFile)
×
276
                return nil
×
277
        }
×
278

279
        config := mdBookConfig{Title: title}
1✔
280

1✔
281
        b := bytes.Buffer{}
1✔
282
        if err := templ.ExecuteTemplate(&b, "book.toml", &config); err != nil {
1✔
283
                return err
×
284
        }
×
285
        if err := os.WriteFile(outFile, b.Bytes(), 0644); err != nil {
1✔
286
                return err
×
287
        }
×
288

289
        cssDir := path.Join(docDir, "css")
1✔
290
        cssFile := path.Join(cssDir, "mdbook.css")
1✔
291
        exists, _, err = fileExists(cssFile)
1✔
292
        if err != nil {
1✔
293
                return err
×
294
        }
×
295
        if exists {
1✔
296
                fmt.Printf("WARNING: MdBook CSS file %s already exists, skip creating\n", cssFile)
×
297
                return nil
×
298
        }
×
299

300
        if err := os.MkdirAll(cssDir, os.ModePerm); err != nil && !os.IsExist(err) {
1✔
301
                return err
×
302
        }
×
303
        css, err := fs.ReadFile(assets.CSS, "css/mdbook.css")
1✔
304
        if err != nil {
1✔
305
                return err
×
306
        }
×
307
        if err := os.WriteFile(path.Join(cssDir, "custom.css"), css, 0644); err != nil {
1✔
308
                return err
×
309
        }
×
310
        return nil
1✔
311
}
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