mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor files
This commit is contained in:
13
vendor/github.com/googleapis/gnostic/generate-gnostic/README.md
generated
vendored
Normal file
13
vendor/github.com/googleapis/gnostic/generate-gnostic/README.md
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# generate-gnostic
|
||||
|
||||
## The gnostic compiler generator
|
||||
|
||||
This directory contains code that generates a protocol buffer
|
||||
representation and supporting code for a JSON schema.
|
||||
|
||||
It is currently used to build models of OpenAPI specifications
|
||||
and extensions which are described as "vendor extensions" in
|
||||
OpenAPI 2.0 and "specification extensions" in OpenAPI 3.0.
|
||||
|
||||
For usage information, run the `generate-gnostic` binary with no
|
||||
options.
|
624
vendor/github.com/googleapis/gnostic/generate-gnostic/domain.go
generated
vendored
Normal file
624
vendor/github.com/googleapis/gnostic/generate-gnostic/domain.go
generated
vendored
Normal file
@ -0,0 +1,624 @@
|
||||
// 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
|
||||
}
|
913
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-compiler.go
generated
vendored
Normal file
913
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-compiler.go
generated
vendored
Normal file
@ -0,0 +1,913 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/googleapis/gnostic/printer"
|
||||
)
|
||||
|
||||
// patternNames hands out unique names for a given string.
|
||||
type patternNames struct {
|
||||
prefix string
|
||||
values map[string]int
|
||||
last int
|
||||
|
||||
specialCase map[string]func(variable string) string
|
||||
}
|
||||
|
||||
// SpecialCaseExpression returns true if the provided regex can be inlined as a faster
|
||||
// expression.
|
||||
func (p *patternNames) SpecialCaseExpression(value, variable string) (code string, ok bool) {
|
||||
fn, ok := p.specialCase[value]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return fn(variable), ok
|
||||
}
|
||||
|
||||
// VariableName returns the variable name for the given value.
|
||||
func (p *patternNames) VariableName(value string) string {
|
||||
num, ok := p.values[value]
|
||||
if !ok {
|
||||
if p.values == nil {
|
||||
p.values = make(map[string]int)
|
||||
}
|
||||
num = p.last
|
||||
p.last++
|
||||
p.values[value] = num
|
||||
}
|
||||
return fmt.Sprintf("%s%d", p.prefix, num)
|
||||
}
|
||||
|
||||
func (p *patternNames) Names() map[string]string {
|
||||
names := make(map[string]string)
|
||||
for value, num := range p.values {
|
||||
names[fmt.Sprintf("%s%d", p.prefix, num)] = value
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// GenerateCompiler generates the compiler code for a domain.
|
||||
func (domain *Domain) GenerateCompiler(packageName string, license string, imports []string) string {
|
||||
code := &printer.Code{}
|
||||
code.Print(license)
|
||||
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.\n")
|
||||
|
||||
// generate package declaration
|
||||
code.Print("package %s\n", packageName)
|
||||
|
||||
code.Print("import (")
|
||||
for _, filename := range imports {
|
||||
code.Print("\"" + filename + "\"")
|
||||
}
|
||||
code.Print(")\n")
|
||||
|
||||
// generate a simple Version() function
|
||||
code.Print("// Version returns the package name (and OpenAPI version).")
|
||||
code.Print("func Version() string {")
|
||||
code.Print(" return \"%s\"", packageName)
|
||||
code.Print("}\n")
|
||||
|
||||
typeNames := domain.sortedTypeNames()
|
||||
|
||||
regexPatterns := &patternNames{
|
||||
prefix: "pattern",
|
||||
specialCase: map[string]func(string) string{
|
||||
"^x-": func(variable string) string { return fmt.Sprintf("strings.HasPrefix(%s, \"x-\")", variable) },
|
||||
"^/": func(variable string) string { return fmt.Sprintf("strings.HasPrefix(%s, \"/\")", variable) },
|
||||
"^": func(_ string) string { return "true" },
|
||||
},
|
||||
}
|
||||
|
||||
// generate NewX() constructor functions for each type
|
||||
for _, typeName := range typeNames {
|
||||
domain.generateConstructorForType(code, typeName, regexPatterns)
|
||||
}
|
||||
|
||||
// generate ResolveReferences() methods for each type
|
||||
for _, typeName := range typeNames {
|
||||
domain.generateResolveReferencesMethodsForType(code, typeName)
|
||||
}
|
||||
|
||||
// generate ToRawInfo() methods for each type
|
||||
for _, typeName := range typeNames {
|
||||
domain.generateToRawInfoMethodForType(code, typeName)
|
||||
}
|
||||
|
||||
domain.generateConstantVariables(code, regexPatterns)
|
||||
|
||||
return code.String()
|
||||
}
|
||||
|
||||
func escapeSlashes(pattern string) string {
|
||||
return strings.Replace(pattern, "\\", "\\\\", -1)
|
||||
}
|
||||
|
||||
var subpatternPattern = regexp.MustCompile("^.*(\\{.*\\}).*$")
|
||||
|
||||
func nameForPattern(regexPatterns *patternNames, pattern string) string {
|
||||
if !strings.HasPrefix(pattern, "^") {
|
||||
if matches := subpatternPattern.FindStringSubmatch(pattern); matches != nil {
|
||||
match := string(matches[1])
|
||||
pattern = strings.Replace(pattern, match, ".*", -1)
|
||||
}
|
||||
}
|
||||
return regexPatterns.VariableName(pattern)
|
||||
}
|
||||
|
||||
func (domain *Domain) generateConstructorForType(code *printer.Code, typeName string, regexPatterns *patternNames) {
|
||||
code.Print("// New%s creates an object of type %s if possible, returning an error if not.", typeName, typeName)
|
||||
code.Print("func New%s(in interface{}, context *compiler.Context) (*%s, error) {", typeName, typeName)
|
||||
code.Print("errors := make([]error, 0)")
|
||||
|
||||
typeModel := domain.TypeModels[typeName]
|
||||
parentTypeName := typeName
|
||||
|
||||
if typeModel.IsStringArray {
|
||||
code.Print("x := &TypeItem{}")
|
||||
code.Print("switch in := in.(type) {")
|
||||
code.Print("case string:")
|
||||
code.Print(" x.Value = make([]string, 0)")
|
||||
code.Print(" x.Value = append(x.Value, in)")
|
||||
code.Print("case []interface{}:")
|
||||
code.Print(" x.Value = make([]string, 0)")
|
||||
code.Print(" for _, v := range in {")
|
||||
code.Print(" value, ok := v.(string)")
|
||||
code.Print(" if ok {")
|
||||
code.Print(" x.Value = append(x.Value, value)")
|
||||
code.Print(" } else {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for string array element: %%+v (%%T)\", value, value)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print(" }")
|
||||
code.Print(" }")
|
||||
code.Print("default:")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for string array: %%+v (%%T)\", in, in)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
} else if typeModel.IsItemArray {
|
||||
if domain.Version == "v2" {
|
||||
code.Print("x := &ItemsItem{}")
|
||||
code.Print("m, ok := compiler.UnpackMap(in)")
|
||||
code.Print("if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for item array: %%+v (%%T)\", in, in)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("} else {")
|
||||
code.Print(" x.Schema = make([]*Schema, 0)")
|
||||
code.Print(" y, err := NewSchema(m, compiler.NewContext(\"<array>\", context))")
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print(" }")
|
||||
code.Print(" x.Schema = append(x.Schema, y)")
|
||||
code.Print("}")
|
||||
} else if domain.Version == "v3" {
|
||||
code.Print("x := &ItemsItem{}")
|
||||
code.Print("m, ok := compiler.UnpackMap(in)")
|
||||
code.Print("if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for item array: %%+v (%%T)\", in, in)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("} else {")
|
||||
code.Print(" x.SchemaOrReference = make([]*SchemaOrReference, 0)")
|
||||
code.Print(" y, err := NewSchemaOrReference(m, compiler.NewContext(\"<array>\", context))")
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print(" }")
|
||||
code.Print(" x.SchemaOrReference = append(x.SchemaOrReference, y)")
|
||||
code.Print("}")
|
||||
}
|
||||
} else if typeModel.IsBlob {
|
||||
code.Print("x := &Any{}")
|
||||
code.Print("bytes, _ := yaml.Marshal(in)")
|
||||
code.Print("x.Yaml = string(bytes)")
|
||||
} else if typeModel.Name == "StringArray" {
|
||||
code.Print("x := &StringArray{}")
|
||||
code.Print("a, ok := in.([]interface{})")
|
||||
code.Print("if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for StringArray: %%+v (%%T)\", in, in)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("} else {")
|
||||
code.Print(" x.Value = make([]string, 0)")
|
||||
code.Print(" for _, s := range a {")
|
||||
code.Print(" x.Value = append(x.Value, s.(string))")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
} else if typeModel.Name == "Primitive" {
|
||||
code.Print(" x := &Primitive{}")
|
||||
code.Print(" matched := false")
|
||||
code.Print(" switch in := in.(type) {")
|
||||
code.Print(" case bool:")
|
||||
code.Print(" x.Oneof = &Primitive_Boolean{Boolean: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case string:")
|
||||
code.Print(" x.Oneof = &Primitive_String_{String_: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int64:")
|
||||
code.Print(" x.Oneof = &Primitive_Integer{Integer: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int32:")
|
||||
code.Print(" x.Oneof = &Primitive_Integer{Integer: int64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int:")
|
||||
code.Print(" x.Oneof = &Primitive_Integer{Integer: int64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float64:")
|
||||
code.Print(" x.Oneof = &Primitive_Number{Number: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float32:")
|
||||
code.Print(" x.Oneof = &Primitive_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" }")
|
||||
code.Print(" if matched {")
|
||||
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
|
||||
code.Print(" errors = make([]error, 0)")
|
||||
code.Print(" }")
|
||||
} else if typeModel.Name == "SpecificationExtension" {
|
||||
code.Print(" x := &SpecificationExtension{}")
|
||||
code.Print(" matched := false")
|
||||
code.Print(" switch in := in.(type) {")
|
||||
code.Print(" case bool:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Boolean{Boolean: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case string:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_String_{String_: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int64:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int32:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float64:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float32:")
|
||||
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" }")
|
||||
code.Print(" if matched {")
|
||||
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
|
||||
code.Print(" errors = make([]error, 0)")
|
||||
code.Print(" }")
|
||||
} else if typeModel.Name == "DefaultType" {
|
||||
code.Print(" x := &DefaultType{}")
|
||||
code.Print(" matched := false")
|
||||
code.Print(" switch in := in.(type) {")
|
||||
code.Print(" case bool:")
|
||||
code.Print(" x.Oneof = &DefaultType_Boolean{Boolean: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case string:")
|
||||
code.Print(" x.Oneof = &DefaultType_String_{String_: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int64:")
|
||||
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int32:")
|
||||
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case int:")
|
||||
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float64:")
|
||||
code.Print(" x.Oneof = &DefaultType_Number{Number: in}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" case float32:")
|
||||
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
|
||||
code.Print(" matched = true")
|
||||
code.Print(" }")
|
||||
code.Print(" if matched {")
|
||||
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
|
||||
code.Print(" errors = make([]error, 0)")
|
||||
code.Print(" }")
|
||||
} else {
|
||||
oneOfWrapper := typeModel.OneOfWrapper
|
||||
|
||||
code.Print("x := &%s{}", typeName)
|
||||
|
||||
if oneOfWrapper {
|
||||
code.Print("matched := false")
|
||||
}
|
||||
|
||||
unpackAtTop := !oneOfWrapper || len(typeModel.Required) > 0
|
||||
if unpackAtTop {
|
||||
code.Print("m, ok := compiler.UnpackMap(in)")
|
||||
code.Print("if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value: %%+v (%%T)\", in, in)")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("} else {")
|
||||
}
|
||||
if len(typeModel.Required) > 0 {
|
||||
// verify that map includes all required keys
|
||||
keyString := ""
|
||||
sort.Strings(typeModel.Required)
|
||||
for _, k := range typeModel.Required {
|
||||
if keyString != "" {
|
||||
keyString += ","
|
||||
}
|
||||
keyString += "\""
|
||||
keyString += k
|
||||
keyString += "\""
|
||||
}
|
||||
code.Print("requiredKeys := []string{%s}", keyString)
|
||||
code.Print("missingKeys := compiler.MissingKeysInMap(m, requiredKeys)")
|
||||
code.Print("if len(missingKeys) > 0 {")
|
||||
code.Print(" message := fmt.Sprintf(\"is missing required %%s: %%+v\", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, \", \"))")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
if !typeModel.Open {
|
||||
// verify that map has no unspecified keys
|
||||
allowedKeys := make([]string, 0)
|
||||
for _, property := range typeModel.Properties {
|
||||
if !property.Implicit {
|
||||
allowedKeys = append(allowedKeys, property.Name)
|
||||
}
|
||||
}
|
||||
sort.Strings(allowedKeys)
|
||||
allowedKeyString := ""
|
||||
for _, allowedKey := range allowedKeys {
|
||||
if allowedKeyString != "" {
|
||||
allowedKeyString += ","
|
||||
}
|
||||
allowedKeyString += "\""
|
||||
allowedKeyString += allowedKey
|
||||
allowedKeyString += "\""
|
||||
}
|
||||
allowedPatternString := ""
|
||||
if typeModel.OpenPatterns != nil {
|
||||
for _, pattern := range typeModel.OpenPatterns {
|
||||
if allowedPatternString != "" {
|
||||
allowedPatternString += ","
|
||||
}
|
||||
allowedPatternString += nameForPattern(regexPatterns, pattern)
|
||||
}
|
||||
}
|
||||
// verify that map includes only allowed keys and patterns
|
||||
code.Print("allowedKeys := []string{%s}", allowedKeyString)
|
||||
if len(allowedPatternString) > 0 {
|
||||
code.Print("allowedPatterns := []*regexp.Regexp{%s}", allowedPatternString)
|
||||
} else {
|
||||
code.Print("var allowedPatterns []*regexp.Regexp")
|
||||
|
||||
}
|
||||
code.Print("invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns)")
|
||||
code.Print("if len(invalidKeys) > 0 {")
|
||||
code.Print(" message := fmt.Sprintf(\"has invalid %%s: %%+v\", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, \", \"))")
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
var fieldNumber = 0
|
||||
for _, propertyModel := range typeModel.Properties {
|
||||
propertyName := propertyModel.Name
|
||||
fieldNumber++
|
||||
propertyType := propertyModel.Type
|
||||
if propertyType == "int" {
|
||||
propertyType = "int64"
|
||||
}
|
||||
var displayName = propertyName
|
||||
if displayName == "$ref" {
|
||||
displayName = "_ref"
|
||||
}
|
||||
if displayName == "$schema" {
|
||||
displayName = "_schema"
|
||||
}
|
||||
displayName = camelCaseToSnakeCase(displayName)
|
||||
|
||||
var line = fmt.Sprintf("%s %s = %d;", propertyType, displayName, fieldNumber)
|
||||
if propertyModel.Repeated {
|
||||
line = "repeated " + line
|
||||
}
|
||||
code.Print("// " + line)
|
||||
|
||||
fieldName := strings.Title(snakeCaseToCamelCase(propertyName))
|
||||
if propertyName == "$ref" {
|
||||
fieldName = "XRef"
|
||||
}
|
||||
|
||||
typeModel, typeFound := domain.TypeModels[propertyType]
|
||||
if typeFound && !typeModel.IsPair {
|
||||
if propertyModel.Repeated {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" // repeated %s", typeModel.Name)
|
||||
code.Print(" x.%s = make([]*%s, 0)", fieldName, typeModel.Name)
|
||||
code.Print(" a, ok := v%d.([]interface{})", fieldNumber)
|
||||
code.Print(" if ok {")
|
||||
code.Print(" for _, item := range a {")
|
||||
code.Print(" y, err := New%s(item, compiler.NewContext(\"%s\", context))", typeModel.Name, propertyName)
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" }")
|
||||
code.Print(" x.%s = append(x.%s, y)", fieldName, fieldName)
|
||||
code.Print(" }")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
} else {
|
||||
if oneOfWrapper {
|
||||
code.Print("{")
|
||||
if !unpackAtTop {
|
||||
code.Print(" m, ok := compiler.UnpackMap(in)")
|
||||
code.Print(" if ok {")
|
||||
}
|
||||
code.Print(" // errors might be ok here, they mean we just don't have the right subtype")
|
||||
code.Print(" t, matchingError := New%s(m, compiler.NewContext(\"%s\", context))", typeModel.Name, propertyName)
|
||||
code.Print(" if matchingError == nil {")
|
||||
code.Print(" x.Oneof = &%s_%s{%s: t}", parentTypeName, typeModel.Name, typeModel.Name)
|
||||
code.Print(" matched = true")
|
||||
code.Print(" } else {")
|
||||
code.Print(" errors = append(errors, matchingError)")
|
||||
code.Print(" }")
|
||||
if !unpackAtTop {
|
||||
code.Print(" }")
|
||||
}
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" var err error")
|
||||
code.Print(" x.%s, err = New%s(v%d, compiler.NewContext(\"%s\", context))",
|
||||
fieldName, typeModel.Name, fieldNumber, propertyName)
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
}
|
||||
}
|
||||
} else if propertyType == "string" {
|
||||
if propertyModel.Repeated {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" v, ok := v%d.([]interface{})", fieldNumber)
|
||||
code.Print(" if ok {")
|
||||
code.Print(" x.%s = compiler.ConvertInterfaceArrayToStringArray(v)", fieldName)
|
||||
code.Print(" } else {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
|
||||
if propertyModel.StringEnumValues != nil {
|
||||
code.Print("// check for valid enum values")
|
||||
code.Print("// %+v", propertyModel.StringEnumValues)
|
||||
|
||||
stringArrayLiteral := "[]string{"
|
||||
for i, item := range propertyModel.StringEnumValues {
|
||||
if i > 0 {
|
||||
stringArrayLiteral += ","
|
||||
}
|
||||
stringArrayLiteral += "\"" + item + "\""
|
||||
}
|
||||
stringArrayLiteral += "}"
|
||||
code.Print("if ok && !compiler.StringArrayContainsValues(%s, x.%s) {", stringArrayLiteral, fieldName)
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v\", v%d)", propertyName, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" x.%s, ok = v%d.(string)", fieldName, fieldNumber)
|
||||
code.Print(" if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print(" }")
|
||||
|
||||
if propertyModel.StringEnumValues != nil {
|
||||
code.Print("// check for valid enum values")
|
||||
code.Print("// %+v", propertyModel.StringEnumValues)
|
||||
|
||||
stringArrayLiteral := "[]string{"
|
||||
for i, item := range propertyModel.StringEnumValues {
|
||||
if i > 0 {
|
||||
stringArrayLiteral += ","
|
||||
}
|
||||
stringArrayLiteral += "\"" + item + "\""
|
||||
}
|
||||
stringArrayLiteral += "}"
|
||||
|
||||
code.Print("if ok && !compiler.StringArrayContainsValue(%s, x.%s) {", stringArrayLiteral, fieldName)
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print("}")
|
||||
}
|
||||
code.Print("}")
|
||||
}
|
||||
} else if propertyType == "float" {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" switch v%d := v%d.(type) {", fieldNumber, fieldNumber)
|
||||
code.Print(" case float64:")
|
||||
code.Print(" x.%s = v%d", fieldName, fieldNumber)
|
||||
code.Print(" case float32:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" case uint64:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" case uint32:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" case int64:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" case int32:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" case int:")
|
||||
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
|
||||
code.Print(" default:")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
} else if propertyType == "int64" {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" t, ok := v%d.(int)", fieldNumber)
|
||||
code.Print(" if ok {")
|
||||
code.Print(" x.%s = int64(t)", fieldName)
|
||||
code.Print(" } else {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
} else if propertyType == "bool" {
|
||||
if oneOfWrapper {
|
||||
propertyName := "Boolean"
|
||||
code.Print("boolValue, ok := in.(bool)")
|
||||
code.Print("if ok {")
|
||||
code.Print(" x.Oneof = &%s_%s{%s: boolValue}", parentTypeName, propertyName, propertyName)
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
|
||||
code.Print("if (v%d != nil) {", fieldNumber)
|
||||
code.Print(" x.%s, ok = v%d.(bool)", fieldName, fieldNumber)
|
||||
code.Print(" if !ok {")
|
||||
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
|
||||
code.Print(" errors = append(errors, compiler.NewError(context, message))")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
}
|
||||
} else {
|
||||
mapTypeName := propertyModel.MapType
|
||||
if mapTypeName != "" {
|
||||
code.Print("// MAP: %s %s", mapTypeName, propertyModel.Pattern)
|
||||
if mapTypeName == "string" {
|
||||
code.Print("x.%s = make([]*NamedString, 0)", fieldName)
|
||||
} else {
|
||||
code.Print("x.%s = make([]*Named%s, 0)", fieldName, mapTypeName)
|
||||
}
|
||||
code.Print("for _, item := range m {")
|
||||
code.Print("k, ok := compiler.StringValue(item.Key)")
|
||||
code.Print("if ok {")
|
||||
code.Print("v := item.Value")
|
||||
if pattern := propertyModel.Pattern; pattern != "" {
|
||||
if inline, ok := regexPatterns.SpecialCaseExpression(pattern, "k"); ok {
|
||||
code.Print("if %s {", inline)
|
||||
} else {
|
||||
code.Print("if %s.MatchString(k) {", nameForPattern(regexPatterns, pattern))
|
||||
}
|
||||
}
|
||||
|
||||
code.Print("pair := &Named" + strings.Title(mapTypeName) + "{}")
|
||||
code.Print("pair.Name = k")
|
||||
|
||||
if mapTypeName == "string" {
|
||||
code.Print("pair.Value = v.(string)")
|
||||
} else if mapTypeName == "Any" {
|
||||
code.Print("result := &Any{}")
|
||||
code.Print("handled, resultFromExt, err := compiler.HandleExtension(context, v, k)")
|
||||
code.Print("if handled {")
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" } else {")
|
||||
code.Print(" bytes, _ := yaml.Marshal(v)")
|
||||
code.Print(" result.Yaml = string(bytes)")
|
||||
code.Print(" result.Value = resultFromExt")
|
||||
code.Print(" pair.Value = result")
|
||||
code.Print(" }")
|
||||
code.Print("} else {")
|
||||
code.Print(" pair.Value, err = NewAny(v, compiler.NewContext(k, context))")
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
|
||||
} else {
|
||||
code.Print("var err error")
|
||||
code.Print("pair.Value, err = New%s(v, compiler.NewContext(k, context))", mapTypeName)
|
||||
code.Print("if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print("}")
|
||||
}
|
||||
code.Print("x.%s = append(x.%s, pair)", fieldName, fieldName)
|
||||
if propertyModel.Pattern != "" {
|
||||
code.Print("}")
|
||||
}
|
||||
code.Print("}")
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("// TODO: %s", propertyType)
|
||||
}
|
||||
}
|
||||
}
|
||||
if unpackAtTop {
|
||||
code.Print("}")
|
||||
}
|
||||
if oneOfWrapper {
|
||||
code.Print("if matched {")
|
||||
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
|
||||
code.Print(" errors = make([]error, 0)")
|
||||
code.Print("}")
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that the return value is in a variable named "x"
|
||||
code.Print(" return x, compiler.NewErrorGroupOrNil(errors)")
|
||||
code.Print("}\n")
|
||||
}
|
||||
|
||||
// ResolveReferences() methods
|
||||
func (domain *Domain) generateResolveReferencesMethodsForType(code *printer.Code, typeName string) {
|
||||
code.Print("// ResolveReferences resolves references found inside %s objects.", typeName)
|
||||
code.Print("func (m *%s) ResolveReferences(root string) (interface{}, error) {", typeName)
|
||||
code.Print("errors := make([]error, 0)")
|
||||
|
||||
typeModel := domain.TypeModels[typeName]
|
||||
if typeModel.OneOfWrapper {
|
||||
// call ResolveReferences on whatever is in the Oneof.
|
||||
for _, propertyModel := range typeModel.Properties {
|
||||
propertyType := propertyModel.Type
|
||||
_, typeFound := domain.TypeModels[propertyType]
|
||||
if typeFound {
|
||||
code.Print("{")
|
||||
code.Print("p, ok := m.Oneof.(*%s_%s)", typeName, propertyType)
|
||||
code.Print("if ok {")
|
||||
if propertyType == "JsonReference" { // Special case for OpenAPI
|
||||
code.Print("info, err := p.%s.ResolveReferences(root)", propertyType)
|
||||
code.Print("if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print("} else if info != nil {")
|
||||
code.Print(" n, err := New%s(info, nil)", typeName)
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print(" } else if n != nil {")
|
||||
code.Print(" *m = *n")
|
||||
code.Print(" return nil, nil")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("_, err := p.%s.ResolveReferences(root)", propertyType)
|
||||
code.Print("if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print("}")
|
||||
}
|
||||
code.Print("}")
|
||||
code.Print("}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, propertyModel := range typeModel.Properties {
|
||||
propertyName := propertyModel.Name
|
||||
var displayName = propertyName
|
||||
if displayName == "$ref" {
|
||||
displayName = "_ref"
|
||||
}
|
||||
if displayName == "$schema" {
|
||||
displayName = "_schema"
|
||||
}
|
||||
displayName = camelCaseToSnakeCase(displayName)
|
||||
|
||||
fieldName := strings.Title(propertyName)
|
||||
if propertyName == "$ref" {
|
||||
fieldName = "XRef"
|
||||
code.Print("if m.XRef != \"\" {")
|
||||
//code.Print("log.Printf(\"%s reference to resolve %%+v\", m.XRef)", typeName)
|
||||
code.Print("info, err := compiler.ReadInfoForRef(root, m.XRef)")
|
||||
|
||||
code.Print("if err != nil {")
|
||||
code.Print(" return nil, err")
|
||||
code.Print("}")
|
||||
//code.Print("log.Printf(\"%%+v\", info)")
|
||||
|
||||
if len(typeModel.Properties) > 1 {
|
||||
code.Print("if info != nil {")
|
||||
code.Print(" replacement, err := New%s(info, nil)", typeName)
|
||||
code.Print(" if err == nil {")
|
||||
code.Print(" *m = *replacement")
|
||||
code.Print(" return m.ResolveReferences(root)")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
code.Print("return info, nil")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
if !propertyModel.Repeated {
|
||||
propertyType := propertyModel.Type
|
||||
typeModel, typeFound := domain.TypeModels[propertyType]
|
||||
if typeFound && !typeModel.IsPair {
|
||||
code.Print("if m.%s != nil {", fieldName)
|
||||
code.Print(" _, err := m.%s.ResolveReferences(root)", fieldName)
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
}
|
||||
} else {
|
||||
propertyType := propertyModel.Type
|
||||
_, typeFound := domain.TypeModels[propertyType]
|
||||
if typeFound {
|
||||
code.Print("for _, item := range m.%s {", fieldName)
|
||||
code.Print("if item != nil {")
|
||||
code.Print(" _, err := item.ResolveReferences(root)")
|
||||
code.Print(" if err != nil {")
|
||||
code.Print(" errors = append(errors, err)")
|
||||
code.Print(" }")
|
||||
code.Print("}")
|
||||
code.Print("}")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
code.Print(" return nil, compiler.NewErrorGroupOrNil(errors)")
|
||||
code.Print("}\n")
|
||||
}
|
||||
|
||||
// ToRawInfo() methods
|
||||
func (domain *Domain) generateToRawInfoMethodForType(code *printer.Code, typeName string) {
|
||||
code.Print("// ToRawInfo returns a description of %s suitable for JSON or YAML export.", typeName)
|
||||
code.Print("func (m *%s) ToRawInfo() interface{} {", typeName)
|
||||
typeModel := domain.TypeModels[typeName]
|
||||
if typeName == "Any" {
|
||||
code.Print("var err error")
|
||||
code.Print("var info1 []yaml.MapSlice")
|
||||
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info1)")
|
||||
code.Print("if err == nil {return info1}")
|
||||
code.Print("var info2 yaml.MapSlice")
|
||||
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info2)")
|
||||
code.Print("if err == nil {return info2}")
|
||||
code.Print("var info3 interface{}")
|
||||
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info3)")
|
||||
code.Print("if err == nil {return info3}")
|
||||
code.Print("return nil")
|
||||
} else if typeName == "StringArray" {
|
||||
code.Print("return m.Value")
|
||||
} else if typeModel.OneOfWrapper {
|
||||
code.Print("// ONE OF WRAPPER")
|
||||
code.Print("// %s", typeModel.Name)
|
||||
for i, item := range typeModel.Properties {
|
||||
code.Print("// %+v", *item)
|
||||
if item.Type == "float" {
|
||||
code.Print("if v%d, ok := m.GetOneof().(*%s_Number); ok {", i, typeName)
|
||||
code.Print("return v%d.Number", i)
|
||||
code.Print("}")
|
||||
} else if item.Type == "bool" {
|
||||
code.Print("if v%d, ok := m.GetOneof().(*%s_Boolean); ok {", i, typeName)
|
||||
code.Print("return v%d.Boolean", i)
|
||||
code.Print("}")
|
||||
} else if item.Type == "string" {
|
||||
code.Print("if v%d, ok := m.GetOneof().(*%s_String_); ok {", i, typeName)
|
||||
code.Print("return v%d.String_", i)
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("v%d := m.Get%s()", i, item.Type)
|
||||
code.Print("if v%d != nil {", i)
|
||||
code.Print(" return v%d.ToRawInfo()", i)
|
||||
code.Print("}")
|
||||
}
|
||||
}
|
||||
code.Print("return nil")
|
||||
} else {
|
||||
code.Print("info := yaml.MapSlice{}")
|
||||
for _, propertyModel := range typeModel.Properties {
|
||||
switch propertyModel.Type {
|
||||
case "string":
|
||||
propertyName := propertyModel.Name
|
||||
if !propertyModel.Repeated {
|
||||
code.Print("if m.%s != \"\" {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
}
|
||||
case "bool":
|
||||
propertyName := propertyModel.Name
|
||||
if !propertyModel.Repeated {
|
||||
code.Print("if m.%s != false {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
}
|
||||
case "int":
|
||||
propertyName := propertyModel.Name
|
||||
if !propertyModel.Repeated {
|
||||
code.Print("if m.%s != 0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
}
|
||||
case "float":
|
||||
propertyName := propertyModel.Name
|
||||
if !propertyModel.Repeated {
|
||||
code.Print("if m.%s != 0.0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
} else {
|
||||
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s})", propertyName, propertyModel.FieldName())
|
||||
code.Print("}")
|
||||
}
|
||||
default:
|
||||
propertyName := propertyModel.Name
|
||||
if propertyName == "value" {
|
||||
code.Print("// %+v", propertyModel)
|
||||
} else if !propertyModel.Repeated {
|
||||
code.Print("if m.%s != nil {", propertyModel.FieldName())
|
||||
if propertyModel.Type == "TypeItem" {
|
||||
code.Print("if len(m.Type.Value) == 1 {")
|
||||
code.Print("info = append(info, yaml.MapItem{\"type\", m.Type.Value[0]})")
|
||||
code.Print("} else {")
|
||||
code.Print("info = append(info, yaml.MapItem{\"type\", m.Type.Value})")
|
||||
code.Print("}")
|
||||
} else if propertyModel.Type == "ItemsItem" {
|
||||
code.Print("items := make([]interface{}, 0)")
|
||||
if domain.Version == "v2" {
|
||||
code.Print("for _, item := range m.Items.Schema {")
|
||||
} else {
|
||||
code.Print("for _, item := range m.Items.SchemaOrReference {")
|
||||
}
|
||||
code.Print(" items = append(items, item.ToRawInfo())")
|
||||
code.Print("}")
|
||||
code.Print("info = append(info, yaml.MapItem{\"items\", items[0]})")
|
||||
} else {
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", m.%s.ToRawInfo()})",
|
||||
propertyName, propertyModel.FieldName())
|
||||
}
|
||||
code.Print("}")
|
||||
code.Print("// %+v", propertyModel)
|
||||
} else if propertyModel.MapType == "string" {
|
||||
code.Print("// %+v", propertyModel)
|
||||
} else if propertyModel.MapType != "" {
|
||||
code.Print("if m.%s != nil {", propertyModel.FieldName())
|
||||
code.Print("for _, item := range m.%s {", propertyModel.FieldName())
|
||||
code.Print("info = append(info, yaml.MapItem{item.Name, item.Value.ToRawInfo()})")
|
||||
code.Print("}")
|
||||
code.Print("}")
|
||||
code.Print("// %+v", propertyModel)
|
||||
} else {
|
||||
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
|
||||
code.Print("items := make([]interface{}, 0)")
|
||||
code.Print("for _, item := range m.%s {", propertyModel.FieldName())
|
||||
code.Print("items = append(items, item.ToRawInfo())")
|
||||
code.Print("}")
|
||||
code.Print("info = append(info, yaml.MapItem{\"%s\", items})", propertyName)
|
||||
code.Print("}")
|
||||
code.Print("// %+v", propertyModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
code.Print("return info")
|
||||
}
|
||||
code.Print("}\n")
|
||||
}
|
||||
|
||||
func (domain *Domain) generateConstantVariables(code *printer.Code, regexPatterns *patternNames) {
|
||||
names := regexPatterns.Names()
|
||||
var sortedNames []string
|
||||
for name, _ := range names {
|
||||
sortedNames = append(sortedNames, name)
|
||||
}
|
||||
sort.Strings(sortedNames)
|
||||
code.Print("var (")
|
||||
for _, name := range sortedNames {
|
||||
code.Print("%s = regexp.MustCompile(\"%s\")", name, escapeSlashes(names[name]))
|
||||
}
|
||||
code.Print(")\n")
|
||||
}
|
363
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-extension.go
generated
vendored
Normal file
363
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-extension.go
generated
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
"github.com/googleapis/gnostic/jsonschema"
|
||||
"github.com/googleapis/gnostic/printer"
|
||||
)
|
||||
|
||||
var protoOptionsForExtensions = []ProtoOption{
|
||||
ProtoOption{
|
||||
Name: "java_multiple_files",
|
||||
Value: "true",
|
||||
Comment: "// This option lets the proto compiler generate Java code inside the package\n" +
|
||||
"// name (see below) instead of inside an outer class. It creates a simpler\n" +
|
||||
"// developer experience by reducing one-level of name nesting and be\n" +
|
||||
"// consistent with most programming languages that don't support outer classes.",
|
||||
},
|
||||
|
||||
ProtoOption{
|
||||
Name: "java_outer_classname",
|
||||
Value: "VendorExtensionProto",
|
||||
Comment: "// The Java outer classname should be the filename in UpperCamelCase. This\n" +
|
||||
"// class is only used to hold proto descriptor, so developers don't need to\n" +
|
||||
"// work with it directly.",
|
||||
},
|
||||
}
|
||||
|
||||
const additionalCompilerCodeWithMain = "" +
|
||||
"func handleExtension(extensionName string, yamlInput string) (bool, proto.Message, error) {\n" +
|
||||
" switch extensionName {\n" +
|
||||
" // All supported extensions\n" +
|
||||
" %s\n" +
|
||||
" default:\n" +
|
||||
" return false, nil, nil\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func main() {\n" +
|
||||
" openapiextension_v1.ProcessExtension(handleExtension)\n" +
|
||||
"}\n"
|
||||
|
||||
const caseStringForObjectTypes = "\n" +
|
||||
"case \"%s\":\n" +
|
||||
"var info yaml.MapSlice\n" +
|
||||
"err := yaml.Unmarshal([]byte(yamlInput), &info)\n" +
|
||||
"if err != nil {\n" +
|
||||
" return true, nil, err\n" +
|
||||
"}\n" +
|
||||
"newObject, err := %s.New%s(info, compiler.NewContext(\"$root\", nil))\n" +
|
||||
"return true, newObject, err"
|
||||
|
||||
const caseStringForWrapperTypes = "\n" +
|
||||
"case \"%s\":\n" +
|
||||
"var info %s\n" +
|
||||
"err := yaml.Unmarshal([]byte(yamlInput), &info)\n" +
|
||||
"if err != nil {\n" +
|
||||
" return true, nil, err\n" +
|
||||
"}\n" +
|
||||
"newObject := &wrappers.%s{Value: info}\n" +
|
||||
"return true, newObject, nil"
|
||||
|
||||
// generateMainFile generates the main program for an extension.
|
||||
func generateMainFile(packageName string, license string, codeBody string, imports []string) string {
|
||||
code := &printer.Code{}
|
||||
code.Print(license)
|
||||
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.\n")
|
||||
|
||||
// generate package declaration
|
||||
code.Print("package %s\n", packageName)
|
||||
|
||||
code.Print("import (")
|
||||
for _, filename := range imports {
|
||||
code.Print("\"" + filename + "\"")
|
||||
}
|
||||
code.Print(")\n")
|
||||
|
||||
code.Print(codeBody)
|
||||
return code.String()
|
||||
}
|
||||
|
||||
func getBaseFileNameWithoutExt(filePath string) string {
|
||||
tmp := filepath.Base(filePath)
|
||||
return tmp[0 : len(tmp)-len(filepath.Ext(tmp))]
|
||||
}
|
||||
|
||||
func toProtoPackageName(input string) string {
|
||||
var out = ""
|
||||
nonAlphaNumeric := regexp.MustCompile("[^0-9A-Za-z_]+")
|
||||
input = nonAlphaNumeric.ReplaceAllString(input, "")
|
||||
for index, character := range input {
|
||||
if character >= 'A' && character <= 'Z' {
|
||||
if index > 0 && input[index-1] != '_' {
|
||||
out += "_"
|
||||
}
|
||||
out += string(character - 'A' + 'a')
|
||||
} else {
|
||||
out += string(character)
|
||||
}
|
||||
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type primitiveTypeInfo struct {
|
||||
goTypeName string
|
||||
wrapperProtoName string
|
||||
}
|
||||
|
||||
var supportedPrimitiveTypeInfos = map[string]primitiveTypeInfo{
|
||||
"string": primitiveTypeInfo{goTypeName: "string", wrapperProtoName: "StringValue"},
|
||||
"number": primitiveTypeInfo{goTypeName: "float64", wrapperProtoName: "DoubleValue"},
|
||||
"integer": primitiveTypeInfo{goTypeName: "int64", wrapperProtoName: "Int64Value"},
|
||||
"boolean": primitiveTypeInfo{goTypeName: "bool", wrapperProtoName: "BoolValue"},
|
||||
// TODO: Investigate how to support arrays. For now users will not be allowed to
|
||||
// create extension handlers for arrays and they will have to use the
|
||||
// plane yaml string as is.
|
||||
}
|
||||
|
||||
type generatedTypeInfo struct {
|
||||
schemaName string
|
||||
// if this is not nil, the schema should be treataed as a primitive type.
|
||||
optionalPrimitiveTypeInfo *primitiveTypeInfo
|
||||
}
|
||||
|
||||
// GenerateExtension generates the implementation of an extension.
|
||||
func GenerateExtension(schemaFile string, outDir string) error {
|
||||
outFileBaseName := getBaseFileNameWithoutExt(schemaFile)
|
||||
extensionNameWithoutXDashPrefix := outFileBaseName[len("x-"):]
|
||||
outDir = path.Join(outDir, "gnostic-x-"+extensionNameWithoutXDashPrefix)
|
||||
protoPackage := toProtoPackageName(extensionNameWithoutXDashPrefix)
|
||||
protoPackageName := strings.ToLower(protoPackage)
|
||||
goPackageName := protoPackageName
|
||||
|
||||
protoOutDirectory := outDir + "/" + "proto"
|
||||
var err error
|
||||
|
||||
projectRoot := os.Getenv("GOPATH") + "/src/github.com/googleapis/gnostic/"
|
||||
baseSchema, err := jsonschema.NewSchemaFromFile(projectRoot + "jsonschema/schema.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseSchema.ResolveRefs()
|
||||
baseSchema.ResolveAllOfs()
|
||||
|
||||
openapiSchema, err := jsonschema.NewSchemaFromFile(schemaFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
openapiSchema.ResolveRefs()
|
||||
openapiSchema.ResolveAllOfs()
|
||||
|
||||
// build a simplified model of the types described by the schema
|
||||
cc := NewDomain(openapiSchema, "v2") // TODO fix for OpenAPI v3
|
||||
|
||||
// create a type for each object defined in the schema
|
||||
extensionNameToMessageName := make(map[string]generatedTypeInfo)
|
||||
schemaErrors := make([]error, 0)
|
||||
supportedPrimitives := make([]string, 0)
|
||||
for key := range supportedPrimitiveTypeInfos {
|
||||
supportedPrimitives = append(supportedPrimitives, key)
|
||||
}
|
||||
sort.Strings(supportedPrimitives)
|
||||
if cc.Schema.Definitions != nil {
|
||||
for _, pair := range *(cc.Schema.Definitions) {
|
||||
definitionName := pair.Name
|
||||
definitionSchema := pair.Value
|
||||
// ensure the id field is set
|
||||
if definitionSchema.ID == nil || len(*(definitionSchema.ID)) == 0 {
|
||||
schemaErrors = append(schemaErrors,
|
||||
fmt.Errorf("schema %s has no 'id' field, which must match the "+
|
||||
"name of the OpenAPI extension that the schema represents",
|
||||
definitionName))
|
||||
} else {
|
||||
if _, ok := extensionNameToMessageName[*(definitionSchema.ID)]; ok {
|
||||
schemaErrors = append(schemaErrors,
|
||||
fmt.Errorf("schema %s and %s have the same 'id' field value",
|
||||
definitionName, extensionNameToMessageName[*(definitionSchema.ID)].schemaName))
|
||||
} else if (definitionSchema.Type == nil) || (*definitionSchema.Type.String == "object") {
|
||||
extensionNameToMessageName[*(definitionSchema.ID)] = generatedTypeInfo{schemaName: definitionName}
|
||||
} else {
|
||||
// this is a primitive type
|
||||
if val, ok := supportedPrimitiveTypeInfos[*definitionSchema.Type.String]; ok {
|
||||
extensionNameToMessageName[*(definitionSchema.ID)] = generatedTypeInfo{schemaName: definitionName, optionalPrimitiveTypeInfo: &val}
|
||||
} else {
|
||||
schemaErrors = append(schemaErrors,
|
||||
fmt.Errorf("Schema %s has type '%s' which is "+
|
||||
"not supported. Supported primitive types are "+
|
||||
"%s.\n", definitionName,
|
||||
*definitionSchema.Type.String,
|
||||
supportedPrimitives))
|
||||
}
|
||||
}
|
||||
}
|
||||
typeName := cc.TypeNameForStub(definitionName)
|
||||
typeModel := cc.BuildTypeForDefinition(typeName, definitionName, definitionSchema)
|
||||
if typeModel != nil {
|
||||
cc.TypeModels[typeName] = typeModel
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(schemaErrors) > 0 {
|
||||
// error has been reported.
|
||||
return compiler.NewErrorGroupOrNil(schemaErrors)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(outDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(protoOutDirectory, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate the protocol buffer description
|
||||
protoOptions := append(protoOptionsForExtensions,
|
||||
ProtoOption{Name: "java_package", Value: "org.openapi.extension." + strings.ToLower(protoPackage), Comment: "// The Java package name must be proto package name with proper prefix."},
|
||||
ProtoOption{Name: "objc_class_prefix", Value: strings.ToLower(protoPackage),
|
||||
Comment: "// A reasonable prefix for the Objective-C symbols generated from the package.\n" +
|
||||
"// It should at a minimum be 3 characters long, all uppercase, and convention\n" +
|
||||
"// is to use an abbreviation of the package name. Something short, but\n" +
|
||||
"// hopefully unique enough to not conflict with things that may come along in\n" +
|
||||
"// the future. 'GPB' is reserved for the protocol buffer implementation itself.",
|
||||
})
|
||||
|
||||
proto := cc.generateProto(protoPackageName, License, protoOptions, nil)
|
||||
protoFilename := path.Join(protoOutDirectory, outFileBaseName+".proto")
|
||||
|
||||
err = ioutil.WriteFile(protoFilename, []byte(proto), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate the compiler
|
||||
compiler := cc.GenerateCompiler(goPackageName, License, []string{
|
||||
"fmt",
|
||||
"regexp",
|
||||
"strings",
|
||||
"github.com/googleapis/gnostic/compiler",
|
||||
"gopkg.in/yaml.v2",
|
||||
})
|
||||
goFilename := path.Join(protoOutDirectory, outFileBaseName+".go")
|
||||
err = ioutil.WriteFile(goFilename, []byte(compiler), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", goFilename).Run()
|
||||
|
||||
// generate the main file.
|
||||
outDirRelativeToGoPathSrc := strings.Replace(outDir, path.Join(os.Getenv("GOPATH"), "src")+"/", "", 1)
|
||||
|
||||
var extensionNameKeys []string
|
||||
for k := range extensionNameToMessageName {
|
||||
extensionNameKeys = append(extensionNameKeys, k)
|
||||
}
|
||||
sort.Strings(extensionNameKeys)
|
||||
|
||||
wrapperTypeIncluded := false
|
||||
var cases string
|
||||
for _, extensionName := range extensionNameKeys {
|
||||
if extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo == nil {
|
||||
cases += fmt.Sprintf(caseStringForObjectTypes, extensionName, goPackageName, extensionNameToMessageName[extensionName].schemaName)
|
||||
} else {
|
||||
wrapperTypeIncluded = true
|
||||
cases += fmt.Sprintf(caseStringForWrapperTypes, extensionName, extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo.goTypeName, extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo.wrapperProtoName)
|
||||
}
|
||||
|
||||
}
|
||||
extMainCode := fmt.Sprintf(additionalCompilerCodeWithMain, cases)
|
||||
imports := []string{
|
||||
"github.com/golang/protobuf/proto",
|
||||
"github.com/googleapis/gnostic/extensions",
|
||||
"github.com/googleapis/gnostic/compiler",
|
||||
"gopkg.in/yaml.v2",
|
||||
outDirRelativeToGoPathSrc + "/" + "proto",
|
||||
}
|
||||
if wrapperTypeIncluded {
|
||||
imports = append(imports, "github.com/golang/protobuf/ptypes/wrappers")
|
||||
}
|
||||
main := generateMainFile("main", License, extMainCode, imports)
|
||||
mainFileName := path.Join(outDir, "main.go")
|
||||
err = ioutil.WriteFile(mainFileName, []byte(main), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// format the compiler
|
||||
return exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", mainFileName).Run()
|
||||
}
|
||||
|
||||
func processExtensionGenCommandline(usage string) error {
|
||||
|
||||
outDir := ""
|
||||
schameFile := ""
|
||||
|
||||
extParamRegex, _ := regexp.Compile("--(.+)=(.+)")
|
||||
|
||||
for i, arg := range os.Args {
|
||||
if i == 0 {
|
||||
continue // skip the tool name
|
||||
}
|
||||
var m [][]byte
|
||||
if m = extParamRegex.FindSubmatch([]byte(arg)); m != nil {
|
||||
flagName := string(m[1])
|
||||
flagValue := string(m[2])
|
||||
switch flagName {
|
||||
case "out_dir":
|
||||
outDir = flagValue
|
||||
default:
|
||||
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage)
|
||||
os.Exit(-1)
|
||||
}
|
||||
} else if arg == "--extension" {
|
||||
continue
|
||||
} else if arg[0] == '-' {
|
||||
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage)
|
||||
os.Exit(-1)
|
||||
} else {
|
||||
schameFile = arg
|
||||
}
|
||||
}
|
||||
|
||||
if schameFile == "" {
|
||||
fmt.Printf("No input json schema specified.\n%s\n", usage)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if outDir == "" {
|
||||
fmt.Printf("Missing output directive.\n%s\n", usage)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if !strings.HasPrefix(getBaseFileNameWithoutExt(schameFile), "x-") {
|
||||
fmt.Printf("Schema file name has to start with 'x-'.\n%s\n", usage)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
return GenerateExtension(schameFile, outDir)
|
||||
}
|
52
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-extension_test.go
generated
vendored
Normal file
52
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-extension_test.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorExtensionGeneratorUnsupportedPrimitive(t *testing.T) {
|
||||
var err error
|
||||
|
||||
output, err := exec.Command(
|
||||
"generator",
|
||||
"--extension",
|
||||
"test/x-unsupportedprimitives.json",
|
||||
"--out_dir=/tmp",
|
||||
).Output()
|
||||
|
||||
outputFile := "x-unsupportedprimitives.errors"
|
||||
_ = ioutil.WriteFile(outputFile, output, 0644)
|
||||
err = exec.Command("diff", outputFile, "test/errors/x-unsupportedprimitives.errors").Run()
|
||||
if err != nil {
|
||||
t.Logf("Diff failed: %+v", err)
|
||||
t.FailNow()
|
||||
} else {
|
||||
// if the test succeeded, clean up
|
||||
os.Remove(outputFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorExtensionGeneratorNameCollision(t *testing.T) {
|
||||
var err error
|
||||
|
||||
output, err := exec.Command(
|
||||
"generator",
|
||||
"--extension",
|
||||
"test/x-extension-name-collision.json",
|
||||
"--out_dir=/tmp",
|
||||
).Output()
|
||||
|
||||
outputFile := "x-extension-name-collision.errors"
|
||||
_ = ioutil.WriteFile(outputFile, output, 0644)
|
||||
err = exec.Command("diff", outputFile, "test/errors/x-extension-name-collision.errors").Run()
|
||||
if err != nil {
|
||||
t.Logf("Diff failed: %+v", err)
|
||||
t.FailNow()
|
||||
} else {
|
||||
// if the test succeeded, clean up
|
||||
os.Remove(outputFile)
|
||||
}
|
||||
}
|
119
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-proto.go
generated
vendored
Normal file
119
vendor/github.com/googleapis/gnostic/generate-gnostic/generate-proto.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/googleapis/gnostic/printer"
|
||||
)
|
||||
|
||||
// ProtoOption represents an option to be added to generated .proto files.
|
||||
type ProtoOption struct {
|
||||
Name string
|
||||
Value string
|
||||
Comment string
|
||||
}
|
||||
|
||||
func (domain *Domain) generateProto(packageName string, license string, options []ProtoOption, imports []string) string {
|
||||
code := &printer.Code{}
|
||||
code.Print(license)
|
||||
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.")
|
||||
code.Print()
|
||||
|
||||
code.Print("syntax = \"proto3\";")
|
||||
code.Print()
|
||||
code.Print("package " + packageName + ";")
|
||||
for _, importString := range imports {
|
||||
code.Print()
|
||||
code.Print("import \"" + importString + "\";")
|
||||
}
|
||||
code.Print()
|
||||
|
||||
// generate option declarations
|
||||
for _, option := range options {
|
||||
commentLines := strings.Split(option.Comment, "\n")
|
||||
for _, commentLine := range commentLines {
|
||||
code.Print(commentLine)
|
||||
}
|
||||
line := "option " + option.Name + " = "
|
||||
if option.Value == "true" || option.Value == "false" {
|
||||
line += option.Value
|
||||
} else {
|
||||
line += "\"" + option.Value + "\""
|
||||
}
|
||||
line += ";\n"
|
||||
code.Print(line)
|
||||
}
|
||||
|
||||
// generate message definitions
|
||||
typeNames := domain.sortedTypeNames()
|
||||
for _, typeName := range typeNames {
|
||||
typeModel := domain.TypeModels[typeName]
|
||||
if typeModel.Description != "" {
|
||||
code.Print("// %s", typeModel.Description)
|
||||
}
|
||||
code.Print("message %s {", typeName)
|
||||
code.Indent()
|
||||
if typeModel.OneOfWrapper {
|
||||
code.Print("oneof oneof {")
|
||||
code.Indent()
|
||||
}
|
||||
var fieldNumber = 0
|
||||
for _, propertyModel := range typeModel.Properties {
|
||||
if propertyModel.Description != "" {
|
||||
code.Print("// %s", propertyModel.Description)
|
||||
}
|
||||
propertyName := propertyModel.Name
|
||||
fieldNumber++
|
||||
propertyType := propertyModel.Type
|
||||
if propertyType == "int" {
|
||||
propertyType = "int64"
|
||||
}
|
||||
if propertyType == "float" {
|
||||
propertyType = "double"
|
||||
}
|
||||
|
||||
// TODO may be remove this.
|
||||
if propertyType == "blob" {
|
||||
propertyType = "string"
|
||||
}
|
||||
|
||||
var displayName = propertyName
|
||||
if displayName == "$ref" {
|
||||
displayName = "_ref"
|
||||
}
|
||||
if displayName == "$schema" {
|
||||
displayName = "_schema"
|
||||
}
|
||||
displayName = camelCaseToSnakeCase(displayName)
|
||||
|
||||
var line = fmt.Sprintf("%s %s = %d;", propertyType, displayName, fieldNumber)
|
||||
if propertyModel.Repeated {
|
||||
line = "repeated " + line
|
||||
}
|
||||
code.Print(line)
|
||||
}
|
||||
if typeModel.OneOfWrapper {
|
||||
code.Outdent()
|
||||
code.Print("}")
|
||||
}
|
||||
code.Outdent()
|
||||
code.Print("}")
|
||||
code.Print()
|
||||
}
|
||||
return code.String()
|
||||
}
|
55
vendor/github.com/googleapis/gnostic/generate-gnostic/helpers.go
generated
vendored
Normal file
55
vendor/github.com/googleapis/gnostic/generate-gnostic/helpers.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// 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 (
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Returns a "snake case" form of a camel-cased string.
|
||||
func camelCaseToSnakeCase(input string) string {
|
||||
out := ""
|
||||
for index, runeValue := range input {
|
||||
//fmt.Printf("%#U starts at byte position %d\n", runeValue, index)
|
||||
if runeValue >= 'A' && runeValue <= 'Z' {
|
||||
if index > 0 {
|
||||
out += "_"
|
||||
}
|
||||
out += string(runeValue - 'A' + 'a')
|
||||
} else {
|
||||
out += string(runeValue)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func snakeCaseToCamelCase(input string) string {
|
||||
out := ""
|
||||
|
||||
words := strings.Split(input, "_")
|
||||
|
||||
for i, word := range words {
|
||||
if (i > 0) && len(word) > 0 {
|
||||
w := []rune(word)
|
||||
w[0] = unicode.ToUpper(w[0])
|
||||
out += string(w)
|
||||
} else {
|
||||
out += word
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
257
vendor/github.com/googleapis/gnostic/generate-gnostic/main.go
generated
vendored
Normal file
257
vendor/github.com/googleapis/gnostic/generate-gnostic/main.go
generated
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
// 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.
|
||||
|
||||
// generator generates Protocol Buffer models and support code from
|
||||
// JSON Schemas. It is used to generate representations of the
|
||||
// OpenAPI Specification and vendor and specification extensions
|
||||
// that are added by third-party OpenAPI authors.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/googleapis/gnostic/jsonschema"
|
||||
)
|
||||
|
||||
// License is the software license applied to generated code.
|
||||
const License = "" +
|
||||
"// Copyright 2017 Google Inc. All Rights Reserved.\n" +
|
||||
"//\n" +
|
||||
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
|
||||
"// you may not use this file except in compliance with the License.\n" +
|
||||
"// You may obtain a copy of the License at\n" +
|
||||
"//\n" +
|
||||
"// http://www.apache.org/licenses/LICENSE-2.0\n" +
|
||||
"//\n" +
|
||||
"// Unless required by applicable law or agreed to in writing, software\n" +
|
||||
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
|
||||
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
|
||||
"// See the License for the specific language governing permissions and\n" +
|
||||
"// limitations under the License.\n"
|
||||
|
||||
func protoOptions(packageName string) []ProtoOption {
|
||||
return []ProtoOption{
|
||||
ProtoOption{
|
||||
Name: "java_multiple_files",
|
||||
Value: "true",
|
||||
Comment: "// This option lets the proto compiler generate Java code inside the package\n" +
|
||||
"// name (see below) instead of inside an outer class. It creates a simpler\n" +
|
||||
"// developer experience by reducing one-level of name nesting and be\n" +
|
||||
"// consistent with most programming languages that don't support outer classes.",
|
||||
},
|
||||
|
||||
ProtoOption{
|
||||
Name: "java_outer_classname",
|
||||
Value: "OpenAPIProto",
|
||||
Comment: "// The Java outer classname should be the filename in UpperCamelCase. This\n" +
|
||||
"// class is only used to hold proto descriptor, so developers don't need to\n" +
|
||||
"// work with it directly.",
|
||||
},
|
||||
|
||||
ProtoOption{
|
||||
Name: "java_package",
|
||||
Value: "org." + packageName,
|
||||
Comment: "// The Java package name must be proto package name with proper prefix.",
|
||||
},
|
||||
|
||||
ProtoOption{
|
||||
Name: "objc_class_prefix",
|
||||
Value: "OAS",
|
||||
Comment: "// A reasonable prefix for the Objective-C symbols generated from the package.\n" +
|
||||
"// It should at a minimum be 3 characters long, all uppercase, and convention\n" +
|
||||
"// is to use an abbreviation of the package name. Something short, but\n" +
|
||||
"// hopefully unique enough to not conflict with things that may come along in\n" +
|
||||
"// the future. 'GPB' is reserved for the protocol buffer implementation itself.",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateOpenAPIModel(version string) error {
|
||||
var input string
|
||||
var filename string
|
||||
var protoPackageName string
|
||||
|
||||
switch version {
|
||||
case "v2":
|
||||
input = "openapi-2.0.json"
|
||||
filename = "OpenAPIv2"
|
||||
protoPackageName = "openapi.v2"
|
||||
case "v3":
|
||||
input = "openapi-3.0.json"
|
||||
filename = "OpenAPIv3"
|
||||
protoPackageName = "openapi.v3"
|
||||
case "discovery":
|
||||
input = "discovery.json"
|
||||
filename = "discovery"
|
||||
protoPackageName = "discovery.v1"
|
||||
default:
|
||||
return fmt.Errorf("Unknown OpenAPI version %s", version)
|
||||
}
|
||||
|
||||
goPackageName := strings.Replace(protoPackageName, ".", "_", -1)
|
||||
|
||||
projectRoot := os.Getenv("GOPATH") + "/src/github.com/googleapis/gnostic/"
|
||||
|
||||
baseSchema, err := jsonschema.NewSchemaFromFile(projectRoot + "jsonschema/schema.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseSchema.ResolveRefs()
|
||||
baseSchema.ResolveAllOfs()
|
||||
|
||||
openapiSchema, err := jsonschema.NewSchemaFromFile(projectRoot + filename + "/" + input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
openapiSchema.ResolveRefs()
|
||||
openapiSchema.ResolveAllOfs()
|
||||
|
||||
// build a simplified model of the types described by the schema
|
||||
cc := NewDomain(openapiSchema, version)
|
||||
// generators will map these patterns to the associated property names
|
||||
// these pattern names are a bit of a hack until we find a more automated way to obtain them
|
||||
|
||||
switch version {
|
||||
case "v2":
|
||||
cc.TypeNameOverrides = map[string]string{
|
||||
"VendorExtension": "Any",
|
||||
}
|
||||
cc.PropertyNameOverrides = map[string]string{
|
||||
"PathItem": "Path",
|
||||
"ResponseValue": "ResponseCode",
|
||||
}
|
||||
case "v3":
|
||||
cc.TypeNameOverrides = map[string]string{
|
||||
"SpecificationExtension": "Any",
|
||||
}
|
||||
cc.PropertyNameOverrides = map[string]string{
|
||||
"PathItem": "Path",
|
||||
"ResponseValue": "ResponseCode",
|
||||
}
|
||||
case "discovery":
|
||||
cc.TypeNameOverrides = map[string]string{}
|
||||
cc.PropertyNameOverrides = map[string]string{}
|
||||
default:
|
||||
return fmt.Errorf("Unknown OpenAPI version %s", version)
|
||||
}
|
||||
|
||||
err = cc.Build()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if true {
|
||||
log.Printf("Type Model:\n%s", cc.Description())
|
||||
}
|
||||
|
||||
// ensure that the target directory exists
|
||||
err = os.MkdirAll(projectRoot+filename, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate the protocol buffer description
|
||||
log.Printf("Generating protocol buffer description")
|
||||
proto := cc.generateProto(protoPackageName, License,
|
||||
protoOptions(goPackageName), []string{"google/protobuf/any.proto"})
|
||||
protoFileName := projectRoot + filename + "/" + filename + ".proto"
|
||||
err = ioutil.WriteFile(protoFileName, []byte(proto), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate the compiler
|
||||
log.Printf("Generating compiler support code")
|
||||
compiler := cc.GenerateCompiler(goPackageName, License, []string{
|
||||
"fmt",
|
||||
"gopkg.in/yaml.v2",
|
||||
"strings",
|
||||
"regexp",
|
||||
"github.com/googleapis/gnostic/compiler",
|
||||
})
|
||||
goFileName := projectRoot + filename + "/" + filename + ".go"
|
||||
err = ioutil.WriteFile(goFileName, []byte(compiler), 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// format the compiler
|
||||
log.Printf("Formatting compiler support code")
|
||||
return exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", goFileName).Run()
|
||||
}
|
||||
|
||||
func usage() string {
|
||||
return fmt.Sprintf(`
|
||||
Usage: %s [OPTIONS]
|
||||
Options:
|
||||
--v2
|
||||
Generate Protocol Buffer representation and support code for OpenAPI v2.
|
||||
Files are read from and written to appropriate locations in the gnostic
|
||||
project directory.
|
||||
--v3
|
||||
Generate Protocol Buffer representation and support code for OpenAPI v3
|
||||
Files are read from and written to appropriate locations in the gnostic
|
||||
project directory.
|
||||
--extension EXTENSION_SCHEMA [EXTENSIONOPTIONS]
|
||||
Generate a gnostic extension that reads a set of OpenAPI extensions.
|
||||
EXTENSION_SCHEMA is the json schema for the OpenAPI extensions to be
|
||||
supported.
|
||||
EXTENSION_OPTIONS
|
||||
--out_dir=PATH: Location for writing extension models and support code.
|
||||
`, path.Base(os.Args[0]))
|
||||
}
|
||||
|
||||
func main() {
|
||||
var openapiVersion = ""
|
||||
var generateExtensions = false
|
||||
|
||||
for i, arg := range os.Args {
|
||||
if i == 0 {
|
||||
continue // skip the tool name
|
||||
}
|
||||
if arg == "--v2" {
|
||||
openapiVersion = "v2"
|
||||
} else if arg == "--v3" {
|
||||
openapiVersion = "v3"
|
||||
} else if arg == "--discovery" {
|
||||
openapiVersion = "discovery"
|
||||
} else if arg == "--extension" {
|
||||
generateExtensions = true
|
||||
break
|
||||
} else {
|
||||
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage())
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
if openapiVersion != "" {
|
||||
err := generateOpenAPIModel(openapiVersion)
|
||||
if err != nil {
|
||||
fmt.Printf("%+v\n", err)
|
||||
}
|
||||
} else if generateExtensions {
|
||||
err := processExtensionGenCommandline(usage())
|
||||
if err != nil {
|
||||
fmt.Printf("%+v\n", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%s\n", usage())
|
||||
}
|
||||
}
|
2
vendor/github.com/googleapis/gnostic/generate-gnostic/test/errors/x-extension-name-collision.errors
generated
vendored
Normal file
2
vendor/github.com/googleapis/gnostic/generate-gnostic/test/errors/x-extension-name-collision.errors
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Schema SampleCompanyTwoPrimitiveString and SampleCompanyOnePrimitiveString have the same 'id' field value.
|
||||
|
2
vendor/github.com/googleapis/gnostic/generate-gnostic/test/errors/x-unsupportedprimitives.errors
generated
vendored
Normal file
2
vendor/github.com/googleapis/gnostic/generate-gnostic/test/errors/x-unsupportedprimitives.errors
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Schema SampleCompanyOnePrimitiveString has type 'unsupportedtype' which is not supported. Supported primitive types are [boolean integer number string].
|
||||
|
12
vendor/github.com/googleapis/gnostic/generate-gnostic/test/x-extension-name-collision.json
generated
vendored
Normal file
12
vendor/github.com/googleapis/gnostic/generate-gnostic/test/x-extension-name-collision.json
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"definitions": {
|
||||
"SampleCompanyOnePrimitiveString": {
|
||||
"type": "string",
|
||||
"id": "x-samplecompanyone-mystr"
|
||||
},
|
||||
"SampleCompanyTwoPrimitiveString": {
|
||||
"type": "string",
|
||||
"id": "x-samplecompanyone-mystr"
|
||||
}
|
||||
}
|
||||
}
|
8
vendor/github.com/googleapis/gnostic/generate-gnostic/test/x-unsupportedprimitives.json
generated
vendored
Normal file
8
vendor/github.com/googleapis/gnostic/generate-gnostic/test/x-unsupportedprimitives.json
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"definitions": {
|
||||
"SampleCompanyOnePrimitiveString": {
|
||||
"type": "unsupportedtype",
|
||||
"id": "x-samplecompanyone-mystr"
|
||||
}
|
||||
}
|
||||
}
|
132
vendor/github.com/googleapis/gnostic/generate-gnostic/types.go
generated
vendored
Normal file
132
vendor/github.com/googleapis/gnostic/generate-gnostic/types.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 (
|
||||
"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
|
||||
}
|
Reference in New Issue
Block a user