mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-22 21:10:22 +00:00
625 lines
22 KiB
Go
625 lines
22 KiB
Go
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/googleapis/gnostic/jsonschema"
|
||
|
)
|
||
|
|
||
|
// Domain models a collection of types that is defined by a schema.
|
||
|
type Domain struct {
|
||
|
TypeModels map[string]*TypeModel // models of the types in the domain
|
||
|
Prefix string // type prefix to use
|
||
|
Schema *jsonschema.Schema // top-level schema
|
||
|
TypeNameOverrides map[string]string // a configured mapping from patterns to type names
|
||
|
PropertyNameOverrides map[string]string // a configured mapping from patterns to property names
|
||
|
ObjectTypeRequests map[string]*TypeRequest // anonymous types implied by type instantiation
|
||
|
MapTypeRequests map[string]string // "NamedObject" types that will be used to implement ordered maps
|
||
|
Version string // OpenAPI Version ("v2" or "v3")
|
||
|
}
|
||
|
|
||
|
// NewDomain creates a domain representation.
|
||
|
func NewDomain(schema *jsonschema.Schema, version string) *Domain {
|
||
|
cc := &Domain{}
|
||
|
cc.TypeModels = make(map[string]*TypeModel, 0)
|
||
|
cc.TypeNameOverrides = make(map[string]string, 0)
|
||
|
cc.PropertyNameOverrides = make(map[string]string, 0)
|
||
|
cc.ObjectTypeRequests = make(map[string]*TypeRequest, 0)
|
||
|
cc.MapTypeRequests = make(map[string]string, 0)
|
||
|
cc.Schema = schema
|
||
|
cc.Version = version
|
||
|
return cc
|
||
|
}
|
||
|
|
||
|
// TypeNameForStub returns a capitalized name to use for a generated type.
|
||
|
func (domain *Domain) TypeNameForStub(stub string) string {
|
||
|
|
||
|
|
||
|
return domain.Prefix + strings.ToUpper(stub[0:1]) + stub[1:len(stub)]
|
||
|
}
|
||
|
|
||
|
// typeNameForReference returns a capitalized name to use for a generated type based on a JSON reference
|
||
|
func (domain *Domain) typeNameForReference(reference string) string {
|
||
|
parts := strings.Split(reference, "/")
|
||
|
first := parts[0]
|
||
|
last := parts[len(parts)-1]
|
||
|
if first == "#" {
|
||
|
return domain.TypeNameForStub(last)
|
||
|
}
|
||
|
return "Schema"
|
||
|
}
|
||
|
|
||
|
// propertyNameForReference returns a property name to use for a JSON reference
|
||
|
func (domain *Domain) propertyNameForReference(reference string) *string {
|
||
|
parts := strings.Split(reference, "/")
|
||
|
first := parts[0]
|
||
|
last := parts[len(parts)-1]
|
||
|
if first == "#" {
|
||
|
return &last
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// arrayItemTypeForSchema determines the item type for arrays defined by a schema
|
||
|
func (domain *Domain) arrayItemTypeForSchema(propertyName string, schema *jsonschema.Schema) string {
|
||
|
// default
|
||
|
itemTypeName := "Any"
|
||
|
|
||
|
if schema.Items != nil {
|
||
|
|
||
|
if schema.Items.SchemaArray != nil {
|
||
|
|
||
|
if len(*(schema.Items.SchemaArray)) > 0 {
|
||
|
ref := (*schema.Items.SchemaArray)[0].Ref
|
||
|
if ref != nil {
|
||
|
itemTypeName = domain.typeNameForReference(*ref)
|
||
|
} else {
|
||
|
types := (*schema.Items.SchemaArray)[0].Type
|
||
|
if types == nil {
|
||
|
// do nothing
|
||
|
} else if (types.StringArray != nil) && len(*(types.StringArray)) == 1 {
|
||
|
itemTypeName = (*types.StringArray)[0]
|
||
|
} else if (types.StringArray != nil) && len(*(types.StringArray)) > 1 {
|
||
|
itemTypeName = fmt.Sprintf("%+v", types.StringArray)
|
||
|
} else if types.String != nil {
|
||
|
itemTypeName = *(types.String)
|
||
|
} else {
|
||
|
itemTypeName = "UNKNOWN"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else if schema.Items.Schema != nil {
|
||
|
types := schema.Items.Schema.Type
|
||
|
|
||
|
if schema.Items.Schema.Ref != nil {
|
||
|
itemTypeName = domain.typeNameForReference(*schema.Items.Schema.Ref)
|
||
|
} else if schema.Items.Schema.OneOf != nil {
|
||
|
// this type is implied by the "oneOf"
|
||
|
itemTypeName = domain.TypeNameForStub(propertyName + "Item")
|
||
|
domain.ObjectTypeRequests[itemTypeName] =
|
||
|
NewTypeRequest(itemTypeName, propertyName, schema.Items.Schema)
|
||
|
} else if types == nil {
|
||
|
// do nothing
|
||
|
} else if (types.StringArray != nil) && len(*(types.StringArray)) == 1 {
|
||
|
itemTypeName = (*types.StringArray)[0]
|
||
|
} else if (types.StringArray != nil) && len(*(types.StringArray)) > 1 {
|
||
|
itemTypeName = fmt.Sprintf("%+v", types.StringArray)
|
||
|
} else if types.String != nil {
|
||
|
itemTypeName = *(types.String)
|
||
|
} else {
|
||
|
itemTypeName = "UNKNOWN"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return itemTypeName
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildTypeProperties(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
if schema.Properties != nil {
|
||
|
for _, pair := range *(schema.Properties) {
|
||
|
propertyName := pair.Name
|
||
|
propertySchema := pair.Value
|
||
|
if propertySchema.Ref != nil {
|
||
|
// the property schema is a reference, so we will add a property with the type of the referenced schema
|
||
|
propertyTypeName := domain.typeNameForReference(*(propertySchema.Ref))
|
||
|
typeProperty := NewTypeProperty()
|
||
|
typeProperty.Name = propertyName
|
||
|
typeProperty.Type = propertyTypeName
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.Type != nil {
|
||
|
// the property schema specifies a type, so add a property with the specified type
|
||
|
if propertySchema.TypeIs("string") {
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, "string")
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
if propertySchema.Enumeration != nil {
|
||
|
allowedValues := make([]string, 0)
|
||
|
for _, enumValue := range *propertySchema.Enumeration {
|
||
|
if enumValue.String != nil {
|
||
|
allowedValues = append(allowedValues, *enumValue.String)
|
||
|
}
|
||
|
}
|
||
|
typeProperty.StringEnumValues = allowedValues
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.TypeIs("boolean") {
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, "bool")
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.TypeIs("number") {
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, "float")
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.TypeIs("integer") {
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, "int")
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.TypeIs("object") {
|
||
|
// the property has an "anonymous" object schema, so define a new type for it and request its creation
|
||
|
anonymousObjectTypeName := domain.TypeNameForStub(propertyName)
|
||
|
domain.ObjectTypeRequests[anonymousObjectTypeName] =
|
||
|
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
|
||
|
// add a property with the type of the requested type
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.TypeIs("array") {
|
||
|
// the property has an array type, so define it as a repeated property of the specified type
|
||
|
propertyTypeName := domain.arrayItemTypeForSchema(propertyName, propertySchema)
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, propertyTypeName)
|
||
|
typeProperty.Repeated = true
|
||
|
if propertySchema.Description != nil {
|
||
|
typeProperty.Description = *propertySchema.Description
|
||
|
}
|
||
|
if typeProperty.Type == "string" {
|
||
|
itemSchema := propertySchema.Items.Schema
|
||
|
if itemSchema != nil {
|
||
|
if itemSchema.Enumeration != nil {
|
||
|
allowedValues := make([]string, 0)
|
||
|
for _, enumValue := range *itemSchema.Enumeration {
|
||
|
if enumValue.String != nil {
|
||
|
allowedValues = append(allowedValues, *enumValue.String)
|
||
|
}
|
||
|
}
|
||
|
typeProperty.StringEnumValues = allowedValues
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else {
|
||
|
log.Printf("ignoring %+v, which has an unsupported property type '%s'", propertyName, propertySchema.Type.Description())
|
||
|
}
|
||
|
} else if propertySchema.IsEmpty() {
|
||
|
// an empty schema can contain anything, so add an accessor for a generic object
|
||
|
typeName := "Any"
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.OneOf != nil {
|
||
|
anonymousObjectTypeName := domain.TypeNameForStub(propertyName + "Item")
|
||
|
domain.ObjectTypeRequests[anonymousObjectTypeName] =
|
||
|
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else if propertySchema.AnyOf != nil {
|
||
|
anonymousObjectTypeName := domain.TypeNameForStub(propertyName + "Item")
|
||
|
domain.ObjectTypeRequests[anonymousObjectTypeName] =
|
||
|
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
|
||
|
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
} else {
|
||
|
log.Printf("ignoring %s.%s, which has an unrecognized schema:\n%+v", typeModel.Name, propertyName, propertySchema.String())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildTypeRequirements(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
if schema.Required != nil {
|
||
|
typeModel.Required = (*schema.Required)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildPatternPropertyAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
if schema.PatternProperties != nil {
|
||
|
typeModel.OpenPatterns = make([]string, 0)
|
||
|
for _, pair := range *(schema.PatternProperties) {
|
||
|
propertyPattern := pair.Name
|
||
|
propertySchema := pair.Value
|
||
|
typeModel.OpenPatterns = append(typeModel.OpenPatterns, propertyPattern)
|
||
|
if propertySchema.Ref != nil {
|
||
|
typeName := domain.typeNameForReference(*propertySchema.Ref)
|
||
|
if _, ok := domain.TypeNameOverrides[typeName]; ok {
|
||
|
typeName = domain.TypeNameOverrides[typeName]
|
||
|
}
|
||
|
propertyName := domain.typeNameForReference(*propertySchema.Ref)
|
||
|
if _, ok := domain.PropertyNameOverrides[propertyName]; ok {
|
||
|
propertyName = domain.PropertyNameOverrides[propertyName]
|
||
|
}
|
||
|
propertyTypeName := fmt.Sprintf("Named%s", typeName)
|
||
|
property := NewTypePropertyWithNameTypeAndPattern(propertyName, propertyTypeName, propertyPattern)
|
||
|
property.Implicit = true
|
||
|
property.MapType = typeName
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildAdditionalPropertyAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
if schema.AdditionalProperties != nil {
|
||
|
if schema.AdditionalProperties.Boolean != nil {
|
||
|
if *schema.AdditionalProperties.Boolean == true {
|
||
|
typeModel.Open = true
|
||
|
propertyName := "additionalProperties"
|
||
|
typeName := "NamedAny"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Implicit = true
|
||
|
property.MapType = "Any"
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
return
|
||
|
}
|
||
|
} else if schema.AdditionalProperties.Schema != nil {
|
||
|
typeModel.Open = true
|
||
|
schema := schema.AdditionalProperties.Schema
|
||
|
if schema.Ref != nil {
|
||
|
propertyName := "additionalProperties"
|
||
|
mapType := domain.typeNameForReference(*schema.Ref)
|
||
|
typeName := fmt.Sprintf("Named%s", mapType)
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Implicit = true
|
||
|
property.MapType = mapType
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
return
|
||
|
} else if schema.Type != nil {
|
||
|
typeName := *schema.Type.String
|
||
|
if typeName == "string" {
|
||
|
propertyName := "additionalProperties"
|
||
|
typeName := "NamedString"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Implicit = true
|
||
|
property.MapType = "string"
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
return
|
||
|
} else if typeName == "array" {
|
||
|
if schema.Items != nil {
|
||
|
itemType := *schema.Items.Schema.Type.String
|
||
|
if itemType == "string" {
|
||
|
propertyName := "additionalProperties"
|
||
|
typeName := "NamedStringArray"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Implicit = true
|
||
|
property.MapType = "StringArray"
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if schema.OneOf != nil {
|
||
|
propertyTypeName := domain.TypeNameForStub(typeModel.Name + "Item")
|
||
|
propertyName := "additionalProperties"
|
||
|
typeName := fmt.Sprintf("Named%s", propertyTypeName)
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Implicit = true
|
||
|
property.MapType = propertyTypeName
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
|
||
|
domain.ObjectTypeRequests[propertyTypeName] =
|
||
|
NewTypeRequest(propertyTypeName, propertyName, schema)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildOneOfAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
oneOfs := schema.OneOf
|
||
|
if oneOfs == nil {
|
||
|
return
|
||
|
}
|
||
|
typeModel.Open = true
|
||
|
typeModel.OneOfWrapper = true
|
||
|
for _, oneOf := range *oneOfs {
|
||
|
if oneOf.Ref != nil {
|
||
|
ref := *oneOf.Ref
|
||
|
typeName := domain.typeNameForReference(ref)
|
||
|
propertyName := domain.propertyNameForReference(ref)
|
||
|
|
||
|
if propertyName != nil {
|
||
|
typeProperty := NewTypePropertyWithNameAndType(*propertyName, typeName)
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
}
|
||
|
} else if oneOf.Type != nil && oneOf.Type.String != nil {
|
||
|
switch *oneOf.Type.String {
|
||
|
case "boolean":
|
||
|
typeProperty := NewTypePropertyWithNameAndType("boolean", "bool")
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
case "integer":
|
||
|
typeProperty := NewTypePropertyWithNameAndType("integer", "int")
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
case "number":
|
||
|
typeProperty := NewTypePropertyWithNameAndType("number", "float")
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
case "string":
|
||
|
typeProperty := NewTypePropertyWithNameAndType("string", "string")
|
||
|
typeModel.addProperty(typeProperty)
|
||
|
default:
|
||
|
log.Printf("Unsupported oneOf:\n%+v", oneOf.String())
|
||
|
}
|
||
|
} else {
|
||
|
log.Printf("Unsupported oneOf:\n%+v", oneOf.String())
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func schemaIsContainedInArray(s1 *jsonschema.Schema, s2 *jsonschema.Schema) bool {
|
||
|
if s2.TypeIs("array") {
|
||
|
if s2.Items.Schema != nil {
|
||
|
if s1.IsEqual(s2.Items.Schema) {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) addAnonymousAccessorForSchema(
|
||
|
typeModel *TypeModel,
|
||
|
schema *jsonschema.Schema,
|
||
|
repeated bool) {
|
||
|
ref := schema.Ref
|
||
|
if ref != nil {
|
||
|
typeName := domain.typeNameForReference(*ref)
|
||
|
propertyName := domain.propertyNameForReference(*ref)
|
||
|
if propertyName != nil {
|
||
|
property := NewTypePropertyWithNameAndType(*propertyName, typeName)
|
||
|
property.Repeated = true
|
||
|
typeModel.addProperty(property)
|
||
|
typeModel.IsItemArray = true
|
||
|
}
|
||
|
} else {
|
||
|
typeName := "string"
|
||
|
propertyName := "value"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.Repeated = true
|
||
|
typeModel.addProperty(property)
|
||
|
typeModel.IsStringArray = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildAnyOfAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
anyOfs := schema.AnyOf
|
||
|
if anyOfs == nil {
|
||
|
return
|
||
|
}
|
||
|
if len(*anyOfs) == 2 {
|
||
|
if schemaIsContainedInArray((*anyOfs)[0], (*anyOfs)[1]) {
|
||
|
//log.Printf("ARRAY OF %+v", (*anyOfs)[0].String())
|
||
|
schema := (*anyOfs)[0]
|
||
|
domain.addAnonymousAccessorForSchema(typeModel, schema, true)
|
||
|
} else if schemaIsContainedInArray((*anyOfs)[1], (*anyOfs)[0]) {
|
||
|
//log.Printf("ARRAY OF %+v", (*anyOfs)[1].String())
|
||
|
schema := (*anyOfs)[1]
|
||
|
domain.addAnonymousAccessorForSchema(typeModel, schema, true)
|
||
|
} else {
|
||
|
for _, anyOf := range *anyOfs {
|
||
|
ref := anyOf.Ref
|
||
|
if ref != nil {
|
||
|
typeName := domain.typeNameForReference(*ref)
|
||
|
propertyName := domain.propertyNameForReference(*ref)
|
||
|
if propertyName != nil {
|
||
|
property := NewTypePropertyWithNameAndType(*propertyName, typeName)
|
||
|
typeModel.addProperty(property)
|
||
|
}
|
||
|
} else {
|
||
|
typeName := "bool"
|
||
|
propertyName := "boolean"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
typeModel.addProperty(property)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
log.Printf("Unhandled anyOfs:\n%s", schema.String())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildDefaultAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
|
||
|
typeModel.Open = true
|
||
|
propertyName := "additionalProperties"
|
||
|
typeName := "NamedAny"
|
||
|
property := NewTypePropertyWithNameAndType(propertyName, typeName)
|
||
|
property.MapType = "Any"
|
||
|
property.Repeated = true
|
||
|
domain.MapTypeRequests[property.MapType] = property.MapType
|
||
|
typeModel.addProperty(property)
|
||
|
}
|
||
|
|
||
|
// BuildTypeForDefinition creates a type representation for a schema definition.
|
||
|
func (domain *Domain) BuildTypeForDefinition(
|
||
|
typeName string,
|
||
|
propertyName string,
|
||
|
schema *jsonschema.Schema) *TypeModel {
|
||
|
if (schema.Type == nil) || (*schema.Type.String == "object") {
|
||
|
return domain.buildTypeForDefinitionObject(typeName, propertyName, schema)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) buildTypeForDefinitionObject(
|
||
|
typeName string,
|
||
|
propertyName string,
|
||
|
schema *jsonschema.Schema) *TypeModel {
|
||
|
typeModel := NewTypeModel()
|
||
|
typeModel.Name = typeName
|
||
|
if schema.IsEmpty() {
|
||
|
domain.buildDefaultAccessors(typeModel, schema)
|
||
|
} else {
|
||
|
if schema.Description != nil {
|
||
|
typeModel.Description = *schema.Description
|
||
|
}
|
||
|
domain.buildTypeProperties(typeModel, schema)
|
||
|
domain.buildTypeRequirements(typeModel, schema)
|
||
|
domain.buildPatternPropertyAccessors(typeModel, schema)
|
||
|
domain.buildAdditionalPropertyAccessors(typeModel, schema)
|
||
|
domain.buildOneOfAccessors(typeModel, schema)
|
||
|
domain.buildAnyOfAccessors(typeModel, schema)
|
||
|
}
|
||
|
return typeModel
|
||
|
}
|
||
|
|
||
|
// Build builds a domain model.
|
||
|
func (domain *Domain) Build() (err error) {
|
||
|
if (domain.Schema == nil) || (domain.Schema.Definitions == nil) {
|
||
|
return errors.New("missing definitions section")
|
||
|
}
|
||
|
// create a type for the top-level schema
|
||
|
typeName := domain.Prefix + "Document"
|
||
|
typeModel := NewTypeModel()
|
||
|
typeModel.Name = typeName
|
||
|
domain.buildTypeProperties(typeModel, domain.Schema)
|
||
|
domain.buildTypeRequirements(typeModel, domain.Schema)
|
||
|
domain.buildPatternPropertyAccessors(typeModel, domain.Schema)
|
||
|
domain.buildAdditionalPropertyAccessors(typeModel, domain.Schema)
|
||
|
domain.buildOneOfAccessors(typeModel, domain.Schema)
|
||
|
domain.buildAnyOfAccessors(typeModel, domain.Schema)
|
||
|
if len(typeModel.Properties) > 0 {
|
||
|
domain.TypeModels[typeName] = typeModel
|
||
|
}
|
||
|
|
||
|
// create a type for each object defined in the schema
|
||
|
if domain.Schema.Definitions != nil {
|
||
|
for _, pair := range *(domain.Schema.Definitions) {
|
||
|
definitionName := pair.Name
|
||
|
definitionSchema := pair.Value
|
||
|
typeName := domain.TypeNameForStub(definitionName)
|
||
|
typeModel := domain.BuildTypeForDefinition(typeName, definitionName, definitionSchema)
|
||
|
if typeModel != nil {
|
||
|
domain.TypeModels[typeName] = typeModel
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// iterate over anonymous object types to be instantiated and generate a type for each
|
||
|
for typeName, typeRequest := range domain.ObjectTypeRequests {
|
||
|
domain.TypeModels[typeRequest.Name] =
|
||
|
domain.buildTypeForDefinitionObject(typeName, typeRequest.PropertyName, typeRequest.Schema)
|
||
|
}
|
||
|
|
||
|
// iterate over map item types to be instantiated and generate a type for each
|
||
|
mapTypeNames := make([]string, 0)
|
||
|
for mapTypeName := range domain.MapTypeRequests {
|
||
|
mapTypeNames = append(mapTypeNames, mapTypeName)
|
||
|
}
|
||
|
sort.Strings(mapTypeNames)
|
||
|
|
||
|
for _, mapTypeName := range mapTypeNames {
|
||
|
typeName := "Named" + strings.Title(mapTypeName)
|
||
|
typeModel := NewTypeModel()
|
||
|
typeModel.Name = typeName
|
||
|
typeModel.Description = fmt.Sprintf(
|
||
|
"Automatically-generated message used to represent maps of %s as ordered (name,value) pairs.",
|
||
|
mapTypeName)
|
||
|
typeModel.IsPair = true
|
||
|
typeModel.PairValueType = mapTypeName
|
||
|
|
||
|
nameProperty := NewTypeProperty()
|
||
|
nameProperty.Name = "name"
|
||
|
nameProperty.Type = "string"
|
||
|
nameProperty.Description = "Map key"
|
||
|
typeModel.addProperty(nameProperty)
|
||
|
|
||
|
valueProperty := NewTypeProperty()
|
||
|
valueProperty.Name = "value"
|
||
|
valueProperty.Type = mapTypeName
|
||
|
valueProperty.Description = "Mapped value"
|
||
|
typeModel.addProperty(valueProperty)
|
||
|
|
||
|
domain.TypeModels[typeName] = typeModel
|
||
|
}
|
||
|
|
||
|
// add a type for string arrays
|
||
|
stringArrayType := NewTypeModel()
|
||
|
stringArrayType.Name = "StringArray"
|
||
|
stringProperty := NewTypeProperty()
|
||
|
stringProperty.Name = "value"
|
||
|
stringProperty.Type = "string"
|
||
|
stringProperty.Repeated = true
|
||
|
stringArrayType.addProperty(stringProperty)
|
||
|
domain.TypeModels[stringArrayType.Name] = stringArrayType
|
||
|
|
||
|
// add a type for "Any"
|
||
|
anyType := NewTypeModel()
|
||
|
anyType.Name = "Any"
|
||
|
anyType.Open = true
|
||
|
anyType.IsBlob = true
|
||
|
valueProperty := NewTypeProperty()
|
||
|
valueProperty.Name = "value"
|
||
|
valueProperty.Type = "google.protobuf.Any"
|
||
|
anyType.addProperty(valueProperty)
|
||
|
yamlProperty := NewTypeProperty()
|
||
|
yamlProperty.Name = "yaml"
|
||
|
yamlProperty.Type = "string"
|
||
|
anyType.addProperty(yamlProperty)
|
||
|
domain.TypeModels[anyType.Name] = anyType
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (domain *Domain) sortedTypeNames() []string {
|
||
|
typeNames := make([]string, 0)
|
||
|
for typeName := range domain.TypeModels {
|
||
|
typeNames = append(typeNames, typeName)
|
||
|
}
|
||
|
sort.Strings(typeNames)
|
||
|
return typeNames
|
||
|
}
|
||
|
|
||
|
// Description returns a string representation of a domain.
|
||
|
func (domain *Domain) Description() string {
|
||
|
typeNames := domain.sortedTypeNames()
|
||
|
result := ""
|
||
|
for _, typeName := range typeNames {
|
||
|
result += domain.TypeModels[typeName].description()
|
||
|
}
|
||
|
return result
|
||
|
}
|