// Copyright 2017 Google LLC. 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 ( "fmt" "strings" "github.com/googleapis/gnostic/jsonschema" ) /// Type Modeling // TypeRequest models types that we encounter during model-building that have no named schema. type TypeRequest struct { Name string // name of type to be created PropertyName string // name of a property that refers to this type Schema *jsonschema.Schema // schema for type OneOfWrapper bool // true if the type wraps "oneOfs" } // NewTypeRequest creates a TypeRequest. func NewTypeRequest(name string, propertyName string, schema *jsonschema.Schema) *TypeRequest { return &TypeRequest{Name: name, PropertyName: propertyName, Schema: schema} } // TypeProperty models type properties, eg. fields. type TypeProperty struct { Name string // name of property Type string // type for property (scalar or message type) StringEnumValues []string // possible values if this is an enumerated string type MapType string // if this property is for a map, the name of the mapped type Repeated bool // true if this property is repeated (an array) Pattern string // if the property is a pattern property, names must match this pattern. Implicit bool // true if this property is implied by a pattern or "additional properties" property Description string // if present, the "description" field in the schema } func (typeProperty *TypeProperty) description() string { result := "" if typeProperty.Description != "" { result += fmt.Sprintf("\t// %+s\n", typeProperty.Description) } if typeProperty.Repeated { result += fmt.Sprintf("\t%s %s repeated %s\n", typeProperty.Name, typeProperty.Type, typeProperty.Pattern) } else { result += fmt.Sprintf("\t%s %s %s \n", typeProperty.Name, typeProperty.Type, typeProperty.Pattern) } return result } // NewTypeProperty creates a TypeProperty func NewTypeProperty() *TypeProperty { return &TypeProperty{} } // NewTypePropertyWithNameAndType creates a TypeProperty func NewTypePropertyWithNameAndType(name string, typeName string) *TypeProperty { return &TypeProperty{Name: name, Type: typeName} } // NewTypePropertyWithNameTypeAndPattern creates a TypeProperty func NewTypePropertyWithNameTypeAndPattern(name string, typeName string, pattern string) *TypeProperty { return &TypeProperty{Name: name, Type: typeName, Pattern: pattern} } // FieldName returns the message field name to use for a property. func (typeProperty *TypeProperty) FieldName() string { propertyName := typeProperty.Name if propertyName == "$ref" { return "XRef" } return strings.Title(snakeCaseToCamelCase(propertyName)) } // TypeModel models types. type TypeModel struct { Name string // type name Properties []*TypeProperty // slice of properties Required []string // required property names OneOfWrapper bool // true if this type wraps "oneof" properties Open bool // open types can have keys outside the specified set OpenPatterns []string // patterns for properties that we allow IsStringArray bool // ugly override IsItemArray bool // ugly override IsBlob bool // ugly override IsPair bool // type is a name-value pair used to support ordered maps PairValueType string // type for pair values (valid if IsPair == true) Description string // if present, the "description" field in the schema } func (typeModel *TypeModel) addProperty(property *TypeProperty) { if typeModel.Properties == nil { typeModel.Properties = make([]*TypeProperty, 0) } typeModel.Properties = append(typeModel.Properties, property) } func (typeModel *TypeModel) description() string { result := "" if typeModel.Description != "" { result += fmt.Sprintf("// %+s\n", typeModel.Description) } var wrapperinfo string if typeModel.OneOfWrapper { wrapperinfo = " oneof wrapper" } result += fmt.Sprintf("%+s%s\n", typeModel.Name, wrapperinfo) for _, property := range typeModel.Properties { result += property.description() } return result } // NewTypeModel creates a TypeModel. func NewTypeModel() *TypeModel { typeModel := &TypeModel{} typeModel.Properties = make([]*TypeProperty, 0) return typeModel } func (typeModel *TypeModel) IsRequired(propertyName string) bool { for _, requiredName := range typeModel.Required { if requiredName == propertyName { return true } } return false }