blob: d974c4753f45758a53e771738b48a98a1942d72f [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package bazel_docgen
import (
"log"
"sort"
pb "go.fuchsia.dev/fuchsia/tools/bazel-docgen/third_party/stardoc"
"golang.org/x/exp/maps"
"gopkg.in/yaml.v2"
)
type supportedDocType int
const (
docTypeRule = iota
docTypeProvider
docTypeStarlarkFunction
docTypeRepositoryRule
)
type tocEntry struct {
Title string `yaml:",omitempty"`
Path string `yaml:",omitempty"`
Heading string `yaml:",omitempty"`
Sections []tocEntry `yaml:"section,omitempty"`
docType int
}
func newTocEntry(title string, filename string, docType int) tocEntry {
return tocEntry{
Title: title,
Path: "/" + filename,
docType: docType,
}
}
func checkDuplicateName(name string, entries map[string]tocEntry) {
if _, ok := entries[name]; ok {
log.Fatalln("Detected multiple entries with the same name: ", name)
}
}
func filterEntries(entries []tocEntry, docType int) []tocEntry {
var filteredEntries []tocEntry
for _, entry := range entries {
if entry.docType == docType {
filteredEntries = append(filteredEntries, entry)
}
}
sort.Slice(filteredEntries, func(i, j int) bool {
return filteredEntries[i].Title < filteredEntries[j].Title
})
return filteredEntries
}
func RenderModuleInfo(roots []pb.ModuleInfo, renderer Renderer, fileProvider FileProvider) {
fileProvider.Open()
entries := make(map[string]tocEntry)
for _, moduleInfo := range roots {
// Render all of our rules
for _, rule := range moduleInfo.GetRuleInfo() {
fileName := "rule_" + rule.RuleName + ".md"
checkDuplicateName(fileName, entries)
if err := renderer.RenderRuleInfo(rule, fileProvider.NewFile(fileName)); err != nil {
panic(err)
}
entries[fileName] = newTocEntry(rule.RuleName, fileName, docTypeRule)
}
// Render all of our providers
for _, provider := range moduleInfo.GetProviderInfo() {
fileName := "provider_" + provider.ProviderName + ".md"
checkDuplicateName(fileName, entries)
if err := renderer.RenderProviderInfo(provider, fileProvider.NewFile(fileName)); err != nil {
panic(err)
}
entries[fileName] = newTocEntry(provider.ProviderName, fileName, docTypeProvider)
}
// Render all of our starlark functions
for _, funcInfo := range moduleInfo.GetFuncInfo() {
fileName := "func_" + funcInfo.FunctionName + ".md"
checkDuplicateName(fileName, entries)
if err := renderer.RenderStarlarkFunctionInfo(funcInfo, fileProvider.NewFile(fileName)); err != nil {
panic(err)
}
entries[fileName] = newTocEntry(funcInfo.FunctionName, fileName, docTypeStarlarkFunction)
}
// Render all of our rules
for _, repoRule := range moduleInfo.GetRepositoryRuleInfo() {
fileName := "repo_rule_" + repoRule.RuleName + ".md"
checkDuplicateName(fileName, entries)
if err := renderer.RenderRepositoryRuleInfo(repoRule, fileProvider.NewFile(fileName)); err != nil {
panic(err)
}
entries[fileName] = newTocEntry(repoRule.RuleName, fileName, docTypeRepositoryRule)
}
}
// Render our README.md
readmeWriter := fileProvider.NewFile("README.md")
readmeWriter.Write([]byte(""))
tocEntries := maps.Values(entries)
toc := []tocEntry{
{
Title: "Overview",
Path: "/README.md",
},
{
Heading: "API",
},
{
Sections: []tocEntry{
{
Title: "Rules",
Sections: filterEntries(tocEntries, docTypeRule),
},
{
Title: "Providers",
Sections: filterEntries(tocEntries, docTypeProvider),
},
{
Title: "Starlark Functions",
Sections: filterEntries(tocEntries, docTypeStarlarkFunction),
},
{
Title: "Repository Rules",
Sections: filterEntries(tocEntries, docTypeRepositoryRule),
},
},
},
}
// Make our table of contents
if yamlData, err := yaml.Marshal(&map[string]interface{}{"toc": toc}); err == nil {
tocWriter := fileProvider.NewFile("_toc.yaml")
tocWriter.Write(yamlData)
}
fileProvider.Close()
}