spruce/cmd/spruce-docgen/main.go
Dan Anglin 71d62ecaf6
refactor: add golangci-lint with code refactoring
Add golangci-lint for linting and refactor the code based on the
feedback from running it.

Changes:

- Add configuration for golangci-lint.
- Break the large function in create.go into smaller ones.
- Rename internal/templateFuncs to internal/templatefuncs to remove
  upper case letters in the package name.
- Add a mage target for lint tests.
2023-08-21 03:07:06 +01:00

166 lines
3.2 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"text/template"
"unicode"
)
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(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)
}