package main import ( "bytes" "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 *schema `json:"additionalProperties"` } func (s *schema) UnmarshalJSON(b []byte) error { if bytes.Equal(b, []byte("true")) || bytes.Equal(b, []byte("false")) { *s = schema{} } else { type rawSchema schema var res rawSchema if err := json.Unmarshal(b, &res); err != nil { return err } *s = schema(res) } return nil } func main() { file, err := os.Open(schemaFile) if err != nil { log.Fatal(err) } defer file.Close() decoder := json.NewDecoder(file) var data schema if err := decoder.Decode(&data); err != nil { log.Fatal(err) } funcMap := template.FuncMap{ "capitalise": title, "type": getType, } t := template.Must(template.New("asciidoc").Funcs(funcMap).Parse(schemaReferenceTemplate)) if err = t.Execute(os.Stdout, data); err != nil { log.Fatal(err) } } func title(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" && s.Type != "object" { 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(<<" + title(refType(s.Items.Ref)) + ">>)" } } if s.Type == "" && s.Ref != "" { return "<<" + title(refType(s.Ref)) + ">>" } if s.Type == "object" { if s.AdditionalProperties != nil && s.AdditionalProperties.Type != "" { return "map(" + s.AdditionalProperties.Type + ")" } return "object" } return "UNKNOWN" } func refType(str string) string { prefix := "#/$defs/" if !strings.HasPrefix(str, prefix) { return "UNKNOWN" } return strings.TrimPrefix(str, prefix) }