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

mlange-42 / modo / 13606558454

01 Mar 2025 04:12PM CUT coverage: 74.172%. Remained the same
13606558454

push

github

web-flow
Fix CI for repo changes (#225)

2375 of 3202 relevant lines covered (74.17%)

48.18 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
        "github.com/mlange-42/modo/internal/util"
16
)
17

18
type MdBook struct{}
19

20
type mdBookConfig struct {
21
        Title string
22
}
23

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

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

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

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

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

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

83
        return nil
1✔
84
}
85

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

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

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

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

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

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

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

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

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

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

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

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

197
        return nil
1✔
198
}
199

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

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

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

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

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

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

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

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

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

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

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

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

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

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