From da2c2e52ff8d7d1ee72c76c2e06252938cf2ca84 Mon Sep 17 00:00:00 2001 From: jakezhu9 Date: Fri, 11 Aug 2023 20:10:46 +0800 Subject: [PATCH 1/4] fix: ignore type for enum and const when generating from json schema --- pkg/tools/gen/genkcl_jsonschema.go | 7 +++---- pkg/tools/gen/testdata/jsonschema/basic/input.json | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/tools/gen/genkcl_jsonschema.go b/pkg/tools/gen/genkcl_jsonschema.go index 8a06ab0f..76e7b07d 100644 --- a/pkg/tools/gen/genkcl_jsonschema.go +++ b/pkg/tools/gen/genkcl_jsonschema.go @@ -145,6 +145,7 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name result.HasDefault = true result.DefaultValue = v.Data case *jsonschema.Enum: + typeList.Items = make([]typeInterface, 0, len(*v)) for _, val := range *v { unmarshalledVal := interface{}(nil) err := json.Unmarshal(val, &unmarshalledVal) @@ -163,14 +164,12 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name logger.GetLogger().Warningf("failed to unmarshal const value: %s", err) continue } - typeList.Items = append(typeList.Items, typeValue{ - Value: unmarshalledVal, - }) + typeList.Items = []typeInterface{typeValue{Value: unmarshalledVal}} result.HasDefault = true result.DefaultValue = unmarshalledVal case *jsonschema.Ref: typeName := strcase.ToCamel(v.Reference[strings.LastIndex(v.Reference, "/")+1:]) - typeList.Items = append(typeList.Items, typeCustom{Name: typeName}) + typeList.Items = []typeInterface{typeCustom{Name: typeName}} case *jsonschema.Defs: for key, val := range *v { ctx.resultMap[key] = convertSchemaFromJsonSchema(ctx, val, key) diff --git a/pkg/tools/gen/testdata/jsonschema/basic/input.json b/pkg/tools/gen/testdata/jsonschema/basic/input.json index 7b441116..fa188821 100644 --- a/pkg/tools/gen/testdata/jsonschema/basic/input.json +++ b/pkg/tools/gen/testdata/jsonschema/basic/input.json @@ -20,6 +20,7 @@ "default": true }, "category": { + "type": "string", "enum": [ "Fiction", "Science", From 4ec0d6fa6d2de30ddd9fe10038596da9d89fa217 Mon Sep 17 00:00:00 2001 From: jakezhu9 Date: Fri, 11 Aug 2023 20:54:01 +0800 Subject: [PATCH 2/4] feat: enhance result naming logic when generating from json schema --- pkg/tools/gen/genkcl_jsonschema.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pkg/tools/gen/genkcl_jsonschema.go b/pkg/tools/gen/genkcl_jsonschema.go index 76e7b07d..3fc08016 100644 --- a/pkg/tools/gen/genkcl_jsonschema.go +++ b/pkg/tools/gen/genkcl_jsonschema.go @@ -72,10 +72,18 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name return convertResult{IsSchema: false} } - result := convertResult{IsSchema: false, Name: name} - if result.Name == "" { - result.Name = "MyType" + // for the name of the result, we prefer $id, then title, then name in parameter + // if none of them exists, "MyType" as default + if id, ok := s.Keywords["$id"].(*jsonschema.ID); ok { + lastSlashIndex := strings.LastIndex(string(*id), "/") + name = strings.Replace(string(*id)[lastSlashIndex+1:], ".json", "", -1) + } else if title, ok := s.Keywords["title"].(*jsonschema.Title); ok { + name = string(*title) + } + if name == "" { + name = "MyType" } + result := convertResult{IsSchema: false, Name: name} isArray := false typeList := typeUnion{} @@ -86,11 +94,6 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name case *jsonschema.Comment: case *jsonschema.SchemaURI: case *jsonschema.ID: - // if the schema has ID, use it as the name - lastSlashIndex := strings.LastIndex(string(*v), "/") - if lastSlashIndex != -1 { - result.Name = strings.Trim(string(*v)[lastSlashIndex+1:], ".json") - } case *jsonschema.Description: result.Description = string(*v) case *jsonschema.Type: From 38b4f1224630a5ac16dc58cff9501a3b82db2deb Mon Sep 17 00:00:00 2001 From: jakezhu9 Date: Fri, 11 Aug 2023 21:12:15 +0800 Subject: [PATCH 3/4] feat: add $ for name conflict with keyword when generating kcl --- pkg/tools/gen/template.go | 32 +++++++++++++++++++ .../gen/testdata/jsonschema/basic/expect.k | 2 ++ .../gen/testdata/jsonschema/basic/input.json | 3 ++ 3 files changed, 37 insertions(+) diff --git a/pkg/tools/gen/template.go b/pkg/tools/gen/template.go index 951cfdb7..b6b97b26 100644 --- a/pkg/tools/gen/template.go +++ b/pkg/tools/gen/template.go @@ -70,7 +70,39 @@ func formatValue(v interface{}) string { } } +var kclKeywords = map[string]struct{}{ + "True": {}, + "False": {}, + "None": {}, + "Undefined": {}, + "import": {}, + "and": {}, + "or": {}, + "in": {}, + "is": {}, + "not": {}, + "as": {}, + "if": {}, + "else": {}, + "elif": {}, + "for": {}, + "schema": {}, + "mixin": {}, + "protocol": {}, + "check": {}, + "assert": {}, + "all": {}, + "any": {}, + "map": {}, + "filter": {}, + "lambda": {}, + "rule": {}, +} + func formatName(name string) string { + if _, ok := kclKeywords[name]; ok { + return fmt.Sprintf("$%s", name) + } return name } diff --git a/pkg/tools/gen/testdata/jsonschema/basic/expect.k b/pkg/tools/gen/testdata/jsonschema/basic/expect.k index dcd051c8..2f380358 100644 --- a/pkg/tools/gen/testdata/jsonschema/basic/expect.k +++ b/pkg/tools/gen/testdata/jsonschema/basic/expect.k @@ -14,6 +14,7 @@ schema Book: price : float, optional available : bool, optional, default is True category : "Fiction" | "Science" | "History", optional + $rule : str, optional """ title: str @@ -21,4 +22,5 @@ schema Book: price?: float available?: bool = True category?: "Fiction" | "Science" | "History" + $rule?: str diff --git a/pkg/tools/gen/testdata/jsonschema/basic/input.json b/pkg/tools/gen/testdata/jsonschema/basic/input.json index fa188821..f3f9f384 100644 --- a/pkg/tools/gen/testdata/jsonschema/basic/input.json +++ b/pkg/tools/gen/testdata/jsonschema/basic/input.json @@ -26,6 +26,9 @@ "Science", "History" ] + }, + "rule": { + "type": "string" } }, "required": [ From 086b3fa26ee8987f7de87a51337a451d65fb81ad Mon Sep 17 00:00:00 2001 From: jakezhu9 Date: Mon, 14 Aug 2023 09:25:04 +0800 Subject: [PATCH 4/4] feat: convert to any for unsupported keywords when generating json schema --- pkg/tools/gen/genkcl_jsonschema.go | 31 ++++++++-- .../testdata/jsonschema/unsupport/expect.k | 39 +++++++++++++ .../testdata/jsonschema/unsupport/input.json | 56 +++++++++++++++++++ 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 pkg/tools/gen/testdata/jsonschema/unsupport/expect.k create mode 100644 pkg/tools/gen/testdata/jsonschema/unsupport/input.json diff --git a/pkg/tools/gen/genkcl_jsonschema.go b/pkg/tools/gen/genkcl_jsonschema.go index 3fc08016..2f735efe 100644 --- a/pkg/tools/gen/genkcl_jsonschema.go +++ b/pkg/tools/gen/genkcl_jsonschema.go @@ -175,7 +175,22 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name typeList.Items = []typeInterface{typeCustom{Name: typeName}} case *jsonschema.Defs: for key, val := range *v { - ctx.resultMap[key] = convertSchemaFromJsonSchema(ctx, val, key) + sch := convertSchemaFromJsonSchema(ctx, val, key) + if !sch.IsSchema { + logger.GetLogger().Warningf("unsupported defining non-object: %s", key) + sch = convertResult{ + IsSchema: true, + Name: key, + schema: schema{ + Name: strcase.ToCamel(key), + HasIndexSignature: true, + IndexSignature: indexSignature{ + Type: typePrimitive(typAny), + }, + }, + } + } + ctx.resultMap[key] = sch } case *jsonschema.AdditionalProperties: switch v.SchemaType { @@ -256,11 +271,19 @@ func convertSchemaFromJsonSchema(ctx convertContext, s *jsonschema.Schema, name if result.IsSchema { result.Type = typeCustom{Name: strcase.ToCamel(name)} + if len(result.Properties) == 0 && !result.HasIndexSignature { + result.HasIndexSignature = true + result.IndexSignature = indexSignature{Type: typePrimitive(typAny)} + } } else { - if isArray { - result.Type = typeArray{Items: typeList} + if len(typeList.Items) != 0 { + if isArray { + result.Type = typeArray{Items: typeList} + } else { + result.Type = typeList + } } else { - result.Type = typeList + result.Type = typePrimitive(typAny) } } result.schema.Name = strcase.ToCamel(result.Name) diff --git a/pkg/tools/gen/testdata/jsonschema/unsupport/expect.k b/pkg/tools/gen/testdata/jsonschema/unsupport/expect.k new file mode 100644 index 00000000..3a20af2d --- /dev/null +++ b/pkg/tools/gen/testdata/jsonschema/unsupport/expect.k @@ -0,0 +1,39 @@ +""" +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 Shop: + """ + Schema for representing a shop information. + In this test case, we use some logic keywords like "oneOf" that can't be directly converted at the moment. To make it still work, we'll convert it into "any" type. + + Attributes + ---------- + products : any, optional + """ + + products?: any + +schema Clothing: + """ + Clothing + """ + + [...str]: any + +schema Product: + """ + Product + + Attributes + ---------- + name : str, optional + price : float, optional + """ + + name?: str + price?: float + + check: + price >= 0 diff --git a/pkg/tools/gen/testdata/jsonschema/unsupport/input.json b/pkg/tools/gen/testdata/jsonschema/unsupport/input.json new file mode 100644 index 00000000..df5a5a81 --- /dev/null +++ b/pkg/tools/gen/testdata/jsonschema/unsupport/input.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/schemas/shop", + "description": "Schema for representing a shop information.\nIn this test case, we use some logic keywords like \"oneOf\" that can't be directly converted at the moment. To make it still work, we'll convert it into \"any\" type.", + "$defs": { + "product": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "price": { + "type": "number", + "minimum": 0 + } + } + }, + "clothing": { + "allOf": [ + { + "$ref": "#/$defs/product" + }, + { + "type": "object", + "properties": { + "type": { + "const": "clothing" + }, + "material": { + "type": "string" + } + } + } + ] + } + }, + "type": "object", + "properties": { + "products": { + "oneOf": [ + { + "$ref": "#/$defs/clothing" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/clothing" + } + }, + { + "const": "empty" + } + ] + } + } +}