1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-30 03:23:08 +03:00

Use refs in jsonschema userconfig generator

This makes it possible to use recursive structures in the user config.
This commit is contained in:
Karim Khaleel
2025-02-22 15:55:19 -05:00
committed by Stefan Haller
parent 62c6ba7d57
commit 30e9bf8a75
11 changed files with 1542 additions and 1795 deletions

View File

@ -2,14 +2,13 @@ package jsonschema
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"github.com/iancoleman/orderedmap"
"github.com/jesseduffield/lazycore/pkg/utils"
"github.com/karimkhaleel/jsonschema"
"github.com/samber/lo"
"gopkg.in/yaml.v3"
@ -106,16 +105,7 @@ func (n *Node) MarshalYAML() (interface{}, error) {
setComment(&keyNode, n.Description)
}
if n.Default != nil {
valueNode := yaml.Node{
Kind: yaml.ScalarNode,
}
err := valueNode.Encode(n.Default)
if err != nil {
return nil, err
}
node.Content = append(node.Content, &keyNode, &valueNode)
} else if len(n.Children) > 0 {
if len(n.Children) > 0 {
childrenNode := yaml.Node{
Kind: yaml.MappingNode,
}
@ -136,62 +126,20 @@ func (n *Node) MarshalYAML() (interface{}, error) {
childrenNode.Content = append(childrenNode.Content, childYaml.(*yaml.Node).Content...)
}
node.Content = append(node.Content, &keyNode, &childrenNode)
} else {
valueNode := yaml.Node{
Kind: yaml.ScalarNode,
}
err := valueNode.Encode(n.Default)
if err != nil {
return nil, err
}
node.Content = append(node.Content, &keyNode, &valueNode)
}
return &node, nil
}
func getDescription(v *orderedmap.OrderedMap) string {
description, ok := v.Get("description")
if !ok {
description = ""
}
return description.(string)
}
func getDefault(v *orderedmap.OrderedMap) (error, any) {
defaultValue, ok := v.Get("default")
if ok {
return nil, defaultValue
}
dataType, ok := v.Get("type")
if ok {
dataTypeString := dataType.(string)
if dataTypeString == "string" {
return nil, ""
}
}
return errors.New("Failed to get default value"), nil
}
func parseNode(parent *Node, name string, value *orderedmap.OrderedMap) {
description := getDescription(value)
err, defaultValue := getDefault(value)
if err == nil {
leaf := &Node{Name: name, Description: description, Default: defaultValue}
parent.Children = append(parent.Children, leaf)
}
properties, ok := value.Get("properties")
if !ok {
return
}
orderedProperties := properties.(orderedmap.OrderedMap)
node := &Node{Name: name, Description: description}
parent.Children = append(parent.Children, node)
keys := orderedProperties.Keys()
for _, name := range keys {
value, _ := orderedProperties.Get(name)
typedValue := value.(orderedmap.OrderedMap)
parseNode(node, name, &typedValue)
}
}
func writeToConfigDocs(config []byte) error {
configPath := utils.GetLazyRootDirectory() + "/docs/Config.md"
markdown, err := os.ReadFile(configPath)
@ -222,31 +170,12 @@ func writeToConfigDocs(config []byte) error {
return nil
}
func GenerateConfigDocs() {
content, err := os.ReadFile(GetSchemaDir() + "/config.json")
if err != nil {
panic("Error reading config.json")
func GenerateConfigDocs(schema *jsonschema.Schema) {
rootNode := &Node{
Children: make([]*Node, 0),
}
schema := orderedmap.New()
err = json.Unmarshal(content, &schema)
if err != nil {
panic("Failed to unmarshal config.json")
}
root, ok := schema.Get("properties")
if !ok {
panic("properties key not found in schema")
}
orderedRoot := root.(orderedmap.OrderedMap)
rootNode := Node{}
for _, name := range orderedRoot.Keys() {
value, _ := orderedRoot.Get(name)
typedValue := value.(orderedmap.OrderedMap)
parseNode(&rootNode, name, &typedValue)
}
recurseOverSchema(schema, schema.Definitions["UserConfig"], rootNode)
var buffer bytes.Buffer
encoder := yaml.NewEncoder(&buffer)
@ -262,8 +191,51 @@ func GenerateConfigDocs() {
config := prepareMarshalledConfig(buffer)
err = writeToConfigDocs(config)
err := writeToConfigDocs(config)
if err != nil {
panic(err)
}
}
func recurseOverSchema(rootSchema, schema *jsonschema.Schema, parent *Node) {
if schema == nil || schema.Properties == nil || schema.Properties.Len() == 0 {
return
}
for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
subSchema := getSubSchema(rootSchema, schema, pair.Key)
// Skip empty objects
if subSchema.Type == "object" && subSchema.Properties == nil {
continue
}
// Skip empty arrays
if isZeroValue(subSchema.Default) && subSchema.Type == "array" {
continue
}
node := Node{
Name: pair.Key,
Description: subSchema.Description,
Default: getZeroValue(subSchema.Default, subSchema.Type),
}
parent.Children = append(parent.Children, &node)
recurseOverSchema(rootSchema, subSchema, &node)
}
}
func getZeroValue(val any, t string) any {
if !isZeroValue(val) {
return val
}
switch t {
case "string":
return ""
case "boolean":
return false
default:
return nil
}
}