spruce/cmd/spruce-docgen/main.go
Dan Anglin b92ab4e437
feat: add JSON schema and document generator
Add the schema for the CV JSON documentation and add an internal tool
called spruce-docgen that generates an AsciiDoc referencing the schema.
2023-08-17 21:51:53 +01:00

132 lines
2.5 KiB
Go

package main
import (
"encoding/json"
"log"
"os"
"strings"
"text/template"
"unicode"
)
var schemaFile = "./schema/cv.schema.json"
var schemaReferenceTemplate = `= JSON schema reference
NOTE: This page was auto-generated with spruce-docgen.
== {{ .Title }}
{{ .Description }}
[%header,cols=3*]
|===
|Field
|Type
|Description
{{- range $key, $property := .Properties }}
{{ print "" }}
|{{ $key }}
|{{ type $property }}
|{{ $property.Description }}
{{- end -}}{{ print "" }}
|===
{{ print "" }}
{{- range $i, $schema := .Defs }}
=== {{ capitalise $i }}
{{ print "" }}
[%header,cols=3*]
|===
|Field
|Type
|Description
{{- range $key, $property := $schema.Properties }}
{{ print "" }}
|{{ $key }}
|{{ type $property }}
|{{ $property.Description }}
{{- end -}}{{ print "" }}
|===
{{ print "" }}
{{- end }}
`
// Schema minimally represents the JSON schema format
type Schema struct {
Title string `json:"title"`
Description string `json:"description"`
Type string `json:"type"`
Properties map[string]*Schema `json:"properties"`
Items *Schema `json:"items"`
Required []string `json:"required"`
Ref string `json:"$ref"`
Defs map[string]*Schema `json:"$defs"`
AdditionalProperties any `json:"additionalProperties"`
}
func main() {
file, err := os.Open(schemaFile)
if err != nil {
log.Fatal(err)
}
defer file.Close()
decoder := json.NewDecoder(file)
var schema Schema
if err := decoder.Decode(&schema); err != nil {
log.Fatal(err)
}
funcMap := template.FuncMap{
"capitalise": capitalise,
"type": getType,
}
t := template.Must(template.New("asciidoc").Funcs(funcMap).Parse(schemaReferenceTemplate))
if err = t.Execute(os.Stdout, schema); err != nil {
log.Fatal(err)
}
}
func capitalise(str string) string {
runes := []rune(str)
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}
func getType(s Schema) string {
if s.Type != "" && s.Type != "array" {
return s.Type
}
if s.Type == "array" {
if s.Items == nil {
return "list(UNKNOWN)"
}
if s.Items.Type != "" {
return "list(" + s.Items.Type + ")"
}
if s.Items.Ref != "" {
return "list(<<" + capitalise(refType(s.Items.Ref)) + ">>)"
}
}
if s.Type == "" && s.Ref != "" {
return "<<" + capitalise(refType(s.Ref)) + ">>"
}
return "UNKNOWN"
}
func refType(str string) string {
split := strings.Split(str, "/")
return split[len(split)-1]
}