Skip to content

Commit

Permalink
fix: generate schema for nested object in array (#197)
Browse files Browse the repository at this point in the history
Signed-off-by: jakezhu9 <[email protected]>
  • Loading branch information
jakezhu9 authored Dec 12, 2023
1 parent 2c72167 commit dfe255f
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 20 deletions.
35 changes: 23 additions & 12 deletions pkg/tools/gen/genkcl_jsonschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/iancoleman/strcase"
Expand All @@ -16,6 +17,7 @@ import (
type convertContext struct {
imports map[string]struct{}
resultMap map[string]convertResult
paths []string
}

type convertResult struct {
Expand All @@ -42,8 +44,9 @@ func (k *kclGenerator) genSchemaFromJsonSchema(w io.Writer, filename string, src
ctx := convertContext{
resultMap: make(map[string]convertResult),
imports: make(map[string]struct{}),
paths: []string{},
}
result := convertSchemaFromJsonSchema(ctx, js,
result := convertSchemaFromJsonSchema(&ctx, js,
strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename)))
if !result.IsSchema {
panic("result is not schema")
Expand All @@ -65,7 +68,7 @@ func (k *kclGenerator) genSchemaFromJsonSchema(w io.Writer, filename string, src
return k.genKcl(w, kclSch)
}

func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name string) convertResult {
func convertSchemaFromJsonSchema(ctx *convertContext, s *jsonschema.Schema, name string) convertResult {
// in jsonschema, type is one of True, False and Object
// we only convert Object type
if s.SchemaType != jsonschema.SchemaTypeObject {
Expand All @@ -84,6 +87,7 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
name = "MyType"
}
result := convertResult{IsSchema: false, Name: name}
ctx.paths = append(ctx.paths, name)

isArray := false
typeList := typeUnion{}
Expand Down Expand Up @@ -113,10 +117,11 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
logger.GetLogger().Warningf("unsupported multiple items: %#v", v)
break
}
for _, i := range v.Schemas {
item := convertSchemaFromJsonSchema(ctx, i, "items")
for i, val := range v.Schemas {
item := convertSchemaFromJsonSchema(ctx, val, "items"+strconv.Itoa(i))
if item.IsSchema {
typeList.Items = append(typeList.Items, typeCustom{Name: item.Name})
ctx.resultMap[item.schema.Name] = item
typeList.Items = append(typeList.Items, typeCustom{Name: item.schema.Name})
} else {
typeList.Items = append(typeList.Items, item.Type)
}
Expand All @@ -132,14 +137,12 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
propSch := convertSchemaFromJsonSchema(ctx, val, key)
_, propSch.Required = required[key]
if propSch.IsSchema {
propSch.Name = strcase.ToCamel(key)
ctx.resultMap[propSch.Name] = propSch
ctx.resultMap[propSch.schema.Name] = propSch
}
propSch.Name = strcase.ToSnake(key)
result.Properties = append(result.Properties, propSch.property)
if !propSch.IsSchema {
for _, validate := range propSch.Validations {
validate.Name = propSch.Name
validate.Name = propSch.property.Name
result.Validations = append(result.Validations, validate)
}
}
Expand Down Expand Up @@ -174,6 +177,8 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
typeName := strcase.ToCamel(v.Reference[strings.LastIndex(v.Reference, "/")+1:])
typeList.Items = []typeInterface{typeCustom{Name: typeName}}
case *jsonschema.Defs:
paths := ctx.paths
ctx.paths = []string{}
for key, val := range *v {
sch := convertSchemaFromJsonSchema(ctx, val, key)
if !sch.IsSchema {
Expand All @@ -192,6 +197,7 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
}
ctx.resultMap[key] = sch
}
ctx.paths = paths
case *jsonschema.AdditionalProperties:
switch v.SchemaType {
case jsonschema.SchemaTypeObject:
Expand Down Expand Up @@ -270,7 +276,13 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
}

if result.IsSchema {
result.Type = typeCustom{Name: strcase.ToCamel(name)}
var s strings.Builder
for _, p := range ctx.paths {
s.WriteString(strcase.ToCamel(p))
}
result.schema.Name = s.String()
result.schema.Description = result.Description
result.Type = typeCustom{Name: strcase.ToCamel(result.schema.Name)}
if len(result.Properties) == 0 && !result.HasIndexSignature {
result.HasIndexSignature = true
result.IndexSignature = indexSignature{Type: typePrimitive(typAny)}
Expand All @@ -286,10 +298,9 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name
result.Type = typePrimitive(typAny)
}
}
result.schema.Name = strcase.ToCamel(result.Name)
result.schema.Description = result.Description
result.property.Name = strcase.ToSnake(result.Name)
result.property.Description = result.Description
ctx.paths = ctx.paths[:len(ctx.paths)-1]
return result
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/tools/gen/testdata/jsonschema/additional/expect.k
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ schema Ethernet:
Attributes
----------
name : str, optional
socket : Socket, optional, default is {"HTTP": 80, "HTTPS": 443}
socket : EthernetSocket, optional, default is {"HTTP": 80, "HTTPS": 443}
"""

name?: str
socket?: Socket = {"HTTP": 80, "HTTPS": 443}
socket?: EthernetSocket = {"HTTP": 80, "HTTPS": 443}

schema Socket:
schema EthernetSocket:
"""
Socket
EthernetSocket
"""

[...str]: int
Expand Down
86 changes: 86 additions & 0 deletions pkg/tools/gen/testdata/jsonschema/nested-items/expect.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
This file was generated by the KCL auto-gen tool. DO NOT EDIT.
Editing this file might prove futile when you re-run the KCL auto-gen generate command.
"""

schema MonacoManifestSchema:
"""
MonacoManifestSchema

Attributes
----------
manifest_version : str, required
The schema version this manifest conforms to - e.g. 1.0
projects : [MonacoManifestSchemaProjectsItems0], required
The projects grouped by this manifest
environment_groups : [MonacoManifestSchemaEnvironmentGroupsItems0], required
The Environment groups to which projects in this manifest are deployed
"""

manifest_version: str
projects: [MonacoManifestSchemaProjectsItems0]
environment_groups: [MonacoManifestSchemaEnvironmentGroupsItems0]

schema MonacoManifestSchemaEnvironmentGroupsItems0:
"""
MonacoManifestSchemaEnvironmentGroupsItems0

Attributes
----------
name : str, optional
The name of this environment group
environments : [MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0], optional
The environments in this group
"""

name?: str
environments?: [MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0]

schema MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0:
"""
MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0

Attributes
----------
name : str, optional
The name of this environment
url : MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0Url, optional
The URL of this environment
"""

name?: str
url?: MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0Url

schema MonacoManifestSchemaEnvironmentGroupsItems0EnvironmentsItems0Url:
"""
The URL of this environment

Attributes
----------
type : str, optional
Optional Type of URL definition.
value : str, optional
The value of the URL, based on type either an URL or environment variable name
"""

type?: str
value?: str

schema MonacoManifestSchemaProjectsItems0:
"""
MonacoManifestSchemaProjectsItems0

Attributes
----------
name : str, required
The name of this project
type : str, optional
Optional Type of this project. Default: Simple
path : str, optional
Optional filepath of the project relative to the manifest.yaml location. Defaults to name
"""

name: str
type?: str
path?: str

81 changes: 81 additions & 0 deletions pkg/tools/gen/testdata/jsonschema/nested-items/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"$id": "https://example.com/monaco.manifest.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Dynatrace Monitoring as Code Manifest File",
"type": "object",
"properties": {
"manifestVersion": {
"type": "string",
"description": "The schema version this manifest conforms to - e.g. 1.0"
},
"projects": {
"type": "array",
"description": "The projects grouped by this manifest",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of this project"
},
"type": {
"type": "string",
"description": "Optional Type of this project. Default: Simple"
},
"path": {
"type": "string",
"description": "Optional filepath of the project relative to the manifest.yaml location. Defaults to name"
}
},
"required": [
"name"
]
}
},
"environmentGroups": {
"description": "The Environment groups to which projects in this manifest are deployed",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of this environment group"
},
"environments": {
"description": "The environments in this group",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of this environment"
},
"url": {
"description": "The URL of this environment",
"type": "object",
"properties": {
"type": {
"description": "Optional Type of URL definition.",
"type": "string"
},
"value": {
"type": "string",
"description": "The value of the URL, based on type either an URL or environment variable name"
}
}
}
}
}
}
}
}
}
},
"required": [
"manifestVersion",
"projects",
"environmentGroups"
]
}
8 changes: 4 additions & 4 deletions pkg/tools/gen/testdata/jsonschema/nested/expect.k
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ schema Book:
Attributes
----------
title : str, optional
author : Author, optional
author : BookAuthor, optional
"""

title?: str
author?: Author
author?: BookAuthor

schema Author:
schema BookAuthor:
"""
Author
BookAuthor

Attributes
----------
Expand Down

0 comments on commit dfe255f

Please sign in to comment.