From 98948941eb54be67a18aa8294ac44d11c15265ed Mon Sep 17 00:00:00 2001 From: Mathias Petermann Date: Thu, 28 Mar 2024 08:30:22 +0100 Subject: [PATCH] Refactor json schema, to allow single type values, or lists if necessary remove schemaTypeFor from OpenAPIDocument decomposition of structs --- pkg/cmd/template/schema_inspect_test.go | 153 ++++++++---------------- pkg/schema/jsonschema.go | 30 ++--- pkg/schema/openapi.go | 4 +- 3 files changed, 69 insertions(+), 118 deletions(-) diff --git a/pkg/cmd/template/schema_inspect_test.go b/pkg/cmd/template/schema_inspect_test.go index 37feeafc..8d9f7e83 100644 --- a/pkg/cmd/template/schema_inspect_test.go +++ b/pkg/cmd/template/schema_inspect_test.go @@ -1079,59 +1079,46 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: int_key: - type: - - integer + type: integer default: 10 bool_key: - type: - - boolean + type: boolean default: true false_key: - type: - - boolean + type: boolean default: false string_key: - type: - - string + type: string default: some text float_key: - type: - - number + type: number format: float default: 9.1 array_of_scalars: - type: - - array + type: array items: - type: - - string + type: string default: "" default: [] array_of_maps: - type: - - array + type: array items: - type: - - object + type: object additionalProperties: false properties: foo: - type: - - string + type: string default: "" bar: - type: - - string + type: string default: "" default: [] ` @@ -1170,62 +1157,49 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: int_key: - type: - - integer + type: integer default: 10 bool_key: - type: - - boolean + type: boolean default: true false_key: - type: - - boolean + type: boolean default: false string_key: - type: - - string + type: string default: some text float_key: - type: - - number + type: number format: float default: 9.1 array_of_scalars: - type: - - array + type: array items: - type: - - integer + type: integer default: 0 default: - 1 - 2 - 3 array_of_maps: - type: - - array + type: array items: - type: - - object + type: object additionalProperties: false properties: bar: - type: - - string + type: string default: "" ree: - type: - - string + type: string default: default default: - bar: thing 1 @@ -1274,13 +1248,11 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: int_key: @@ -1314,8 +1286,7 @@ properties: - array - "null" items: - type: - - integer + type: integer default: 0 default: null array_of_maps: @@ -1323,8 +1294,7 @@ properties: - array - "null" items: - type: - - object + type: object additionalProperties: false properties: bar: @@ -1407,8 +1377,7 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: @@ -1452,22 +1421,18 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: int_key: - type: - - integer + type: integer default: 0 array_of_scalars: - type: - - array + type: array items: type: - "null" @@ -1479,20 +1444,16 @@ properties: default: "" default: [] array_of_maps: - type: - - array + type: array items: - type: - - object + type: object additionalProperties: false properties: foo: - type: - - string + type: string default: "" bar: - type: - - string + type: string default: "" default: [] ` @@ -1548,13 +1509,11 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: int_key: @@ -1588,8 +1547,7 @@ properties: - array - "null" items: - type: - - integer + type: integer default: 0 default: - 1 @@ -1600,8 +1558,7 @@ properties: - array - "null" items: - type: - - object + type: object additionalProperties: false properties: bar: @@ -1661,48 +1618,40 @@ foo: expected := `$schema: https://json-schema.org/draft/2020-12/schema $id: https://example.biz/schema/ytt/data-values.json description: Schema for data values, generated by ytt -type: -- object +type: object additionalProperties: false properties: foo: - type: - - object + type: object additionalProperties: false properties: range_key: - type: - - integer + type: integer default: 10 minimum: 0 maximum: 100 min_key: - type: - - integer + type: integer default: 10 minimum: 0 max_key: - type: - - integer + type: integer default: 10 maximum: 100 string_key: - type: - - string + type: string default: "" minLength: 1 maxLength: 10 one_of_integers: - type: - - integer + type: integer default: 1 enum: - 1 - 2 - 3 one_of_strings: - type: - - string + type: string default: one enum: - one diff --git a/pkg/schema/jsonschema.go b/pkg/schema/jsonschema.go index 74c0684d..09013dee 100644 --- a/pkg/schema/jsonschema.go +++ b/pkg/schema/jsonschema.go @@ -12,29 +12,29 @@ import ( // JSONSchemaDocument holds the document type used for creating an JSON Schema document type JSONSchemaDocument struct { - OpenAPIDocument + docType *DocumentType } // NewJSONSchemaDocument creates an instance of an OpenAPIDocument based on the given DocumentType func NewJSONSchemaDocument(docType *DocumentType) *JSONSchemaDocument { - return &JSONSchemaDocument{*NewOpenAPIDocument(docType)} + return &JSONSchemaDocument{docType} } // AsDocument generates a new AST of this OpenAPI v3.0.x document, populating the `schemas:` section with the // type information contained in `docType`. func (j *JSONSchemaDocument) AsDocument() *yamlmeta.Document { - openAPIProperties := j.calculateProperties(j.docType) + jsonSchemaProperties := j.calculateProperties(j.docType) - openAPIProperties.Items = append( + jsonSchemaProperties.Items = append( []*yamlmeta.MapItem{ {Key: "$schema", Value: "https://json-schema.org/draft/2020-12/schema"}, {Key: "$id", Value: "https://example.biz/schema/ytt/data-values.json"}, {Key: "description", Value: "Schema for data values, generated by ytt"}, }, - openAPIProperties.Items..., + jsonSchemaProperties.Items..., ) - return &yamlmeta.Document{Value: openAPIProperties} + return &yamlmeta.Document{Value: jsonSchemaProperties} } func (j *JSONSchemaDocument) calculateProperties(schemaVal interface{}) *yamlmeta.Map { @@ -44,7 +44,7 @@ func (j *JSONSchemaDocument) calculateProperties(schemaVal interface{}) *yamlmet case *MapType: var items openAPIKeys items = append(items, collectDocumentation(typedValue)...) - items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: &yamlmeta.Array{Items: []*yamlmeta.ArrayItem{{Value: "object"}}}}) + items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: "object"}) items = append(items, &yamlmeta.MapItem{Key: additionalPropsProp, Value: false}) var properties []*yamlmeta.MapItem @@ -60,7 +60,7 @@ func (j *JSONSchemaDocument) calculateProperties(schemaVal interface{}) *yamlmet var items openAPIKeys items = append(items, collectDocumentation(typedValue)...) - items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: &yamlmeta.Array{Items: []*yamlmeta.ArrayItem{{Value: "array"}}}}) + items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: "array"}) items = append(items, &yamlmeta.MapItem{Key: defaultProp, Value: typedValue.GetDefaultValue()}) valueType := typedValue.GetValueType().(*ArrayItemType) @@ -74,9 +74,8 @@ func (j *JSONSchemaDocument) calculateProperties(schemaVal interface{}) *yamlmet items = append(items, collectDocumentation(typedValue)...) items = append(items, &yamlmeta.MapItem{Key: defaultProp, Value: typedValue.GetDefaultValue()}) - typeString := j.openAPITypeFor(typedValue) - - items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: &yamlmeta.Array{Items: []*yamlmeta.ArrayItem{{Value: typeString}}}}) + typeString := schemaTypeFor(typedValue) + items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: typeString}) items = append(items, convertValidations(typedValue.GetValidationMap())...) @@ -94,11 +93,14 @@ func (j *JSONSchemaDocument) calculateProperties(schemaVal interface{}) *yamlmet // we need to append the "null" type to the list of types for i := 0; i < len(properties.Items); i++ { if properties.Items[i].Key == "type" { + // this is a map item with a single valeu, we now need to convert it to an array typeItem := properties.Items[i] - // in json schema nullable is represented as an array of types with "null" (as a string!) as one of the types - typeItem.Value.(*yamlmeta.Array).Items = append(typeItem.Value.(*yamlmeta.Array).Items, &yamlmeta.ArrayItem{Value: "null"}) + nullableItem := &yamlmeta.MapItem{Key: "type", Value: &yamlmeta.Array{Items: []*yamlmeta.ArrayItem{ + {Value: typeItem.Value}, // this is the original type + {Value: "null"}, + }}} - items = append(items, typeItem) + items = append(items, nullableItem) } else { items = append(items, properties.Items[i]) } diff --git a/pkg/schema/openapi.go b/pkg/schema/openapi.go index 69d69900..7c77aecc 100644 --- a/pkg/schema/openapi.go +++ b/pkg/schema/openapi.go @@ -131,7 +131,7 @@ func (o *OpenAPIDocument) calculateProperties(schemaVal interface{}) *yamlmeta.M items = append(items, collectDocumentation(typedValue)...) items = append(items, &yamlmeta.MapItem{Key: defaultProp, Value: typedValue.GetDefaultValue()}) - typeString := o.openAPITypeFor(typedValue) + typeString := schemaTypeFor(typedValue) items = append(items, &yamlmeta.MapItem{Key: typeProp, Value: typeString}) items = append(items, convertValidations(typedValue.GetValidationMap())...) @@ -204,7 +204,7 @@ func convertValidations(validations map[string]interface{}) []*yamlmeta.MapItem return items } -func (o *OpenAPIDocument) openAPITypeFor(astType *ScalarType) string { +func schemaTypeFor(astType *ScalarType) string { switch astType.ValueType { case StringType: return "string"