168 lines
3.3 KiB
Go
168 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
"unicode"
|
|
)
|
|
|
|
var schemaReferenceTemplate = `---
|
|
title: "Spruce - JSON schema reference"
|
|
---
|
|
= 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(data []byte) error {
|
|
if bytes.Equal(data, []byte("true")) || bytes.Equal(data, []byte("false")) {
|
|
*s = schema{}
|
|
} else {
|
|
type rawSchema schema
|
|
var res rawSchema
|
|
if err := json.Unmarshal(data, &res); err != nil {
|
|
return fmt.Errorf("unable to unmarshal to rawSchema; %w", err)
|
|
}
|
|
|
|
*s = schema(res)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
schemaFile := "./schema/cv.schema.json"
|
|
|
|
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.Panic(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.Panic(err)
|
|
}
|
|
}
|
|
|
|
func title(str string) string {
|
|
runes := []rune(str)
|
|
|
|
runes[0] = unicode.ToUpper(runes[0])
|
|
|
|
return string(runes)
|
|
}
|
|
|
|
const (
|
|
typeArray = "array"
|
|
typeObject = "object"
|
|
)
|
|
|
|
func getType(data schema) string {
|
|
if data.Type != "" && data.Type != typeArray && data.Type != typeObject {
|
|
return data.Type
|
|
}
|
|
|
|
if data.Type == typeArray {
|
|
switch {
|
|
case data.Items == nil:
|
|
return "list(UNKNOWN)"
|
|
case data.Items.Type != "":
|
|
return "list(" + data.Items.Type + ")"
|
|
case data.Items.Ref != "":
|
|
return "list(<<" + title(refType(data.Items.Ref)) + ">>)"
|
|
default:
|
|
return "list(UNKNOWN)"
|
|
}
|
|
}
|
|
|
|
if data.Type == "" && data.Ref != "" {
|
|
return "<<" + title(refType(data.Ref)) + ">>"
|
|
}
|
|
|
|
if data.Type == typeObject {
|
|
if data.AdditionalProperties.Type != "" {
|
|
return "map(" + data.AdditionalProperties.Type + ")"
|
|
}
|
|
|
|
return typeObject
|
|
}
|
|
|
|
return "UNKNOWN"
|
|
}
|
|
|
|
func refType(str string) string {
|
|
prefix := "#/$defs/"
|
|
if !strings.HasPrefix(str, prefix) {
|
|
return "UNKNOWN"
|
|
}
|
|
|
|
return strings.TrimPrefix(str, prefix)
|
|
}
|