pkg/asyncapi/v2/v2.go (682 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You 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 v2 import ( "github.com/apache/incubator-eventmesh/eventmesh-catalog-go/pkg/asyncapi" ) // Constants for Operation Types. const ( OperationTypePublish asyncapi.OperationType = "publish" OperationTypeSubscribe asyncapi.OperationType = "subscribe" ) type Info struct { TitleField string `mapstructure:"title" json:"title"` VersionField string `mapstructure:"version" json:"version"` } func (info *Info) Title() string { return info.TitleField } func (info *Info) Version() string { return info.VersionField } type Document struct { Extendable InfoField Info `mapstructure:"info" json:"info"` ServersField map[string]Server `mapstructure:"servers" json:"servers"` ChannelsField map[string]Channel `mapstructure:"channels" json:"channels"` } func (d Document) Info() asyncapi.Info { return &d.InfoField } func (d Document) ApplicationPublishableChannels() []asyncapi.Channel { return d.filterChannels(func(operation asyncapi.Operation) bool { return operation.IsApplicationPublishing() }) } func (d Document) ApplicationPublishableMessages() []asyncapi.Message { return d.filterMessages(func(operation asyncapi.Operation) bool { return operation.IsApplicationPublishing() }) } func (d Document) ApplicationPublishOperations() []asyncapi.Operation { return d.filterOperations(func(operation asyncapi.Operation) bool { return operation.IsApplicationPublishing() }) } func (d Document) ApplicationSubscribableChannels() []asyncapi.Channel { return d.filterChannels(func(operation asyncapi.Operation) bool { return operation.IsApplicationSubscribing() }) } func (d Document) ApplicationSubscribableMessages() []asyncapi.Message { return d.filterMessages(func(operation asyncapi.Operation) bool { return operation.IsApplicationSubscribing() }) } func (d Document) ApplicationSubscribeOperations() []asyncapi.Operation { return d.filterOperations(func(operation asyncapi.Operation) bool { return operation.IsApplicationSubscribing() }) } func (d Document) Channels() []asyncapi.Channel { var channels []asyncapi.Channel for _, c := range d.ChannelsField { channels = append(channels, c) } return channels } func (d Document) HasChannels() bool { return len(d.ChannelsField) > 0 } func (d Document) ClientPublishableChannels() []asyncapi.Channel { return d.filterChannels(func(operation asyncapi.Operation) bool { return operation.IsClientPublishing() }) } func (d Document) ClientPublishableMessages() []asyncapi.Message { return d.filterMessages(func(operation asyncapi.Operation) bool { return operation.IsClientPublishing() }) } func (d Document) ClientPublishOperations() []asyncapi.Operation { return d.filterOperations(func(operation asyncapi.Operation) bool { return operation.IsClientPublishing() }) } func (d Document) ClientSubscribableChannels() []asyncapi.Channel { return d.filterChannels(func(operation asyncapi.Operation) bool { return operation.IsClientSubscribing() }) } func (d Document) ClientSubscribableMessages() []asyncapi.Message { return d.filterMessages(func(operation asyncapi.Operation) bool { return operation.IsClientSubscribing() }) } func (d Document) ClientSubscribeOperations() []asyncapi.Operation { return d.filterOperations(func(operation asyncapi.Operation) bool { return operation.IsClientSubscribing() }) } func (d Document) Messages() []asyncapi.Message { var messages []asyncapi.Message for _, c := range d.Channels() { messages = append(messages, c.Messages()...) } return messages } func (d Document) Server(name string) (asyncapi.Server, bool) { s, ok := d.ServersField[name] return s, ok } func (d Document) Servers() []asyncapi.Server { var servers []asyncapi.Server for _, s := range d.ServersField { servers = append(servers, s) } return servers } func (d Document) HasServers() bool { return len(d.ServersField) > 0 } func (d Document) filterChannels(filter func(operation asyncapi.Operation) bool) []asyncapi.Channel { var channels []asyncapi.Channel for _, c := range d.Channels() { for _, o := range c.Operations() { if filter(o) { channels = append(channels, c) } } } return channels } func (d Document) filterMessages(filter func(operation asyncapi.Operation) bool) []asyncapi.Message { var messages []asyncapi.Message for _, c := range d.Channels() { for _, o := range c.Operations() { if filter(o) { messages = append(messages, o.Messages()...) } } } return messages } func (d Document) filterOperations(filter func(operation asyncapi.Operation) bool) []asyncapi.Operation { var operations []asyncapi.Operation for _, c := range d.Channels() { for _, o := range c.Operations() { if filter(o) { operations = append(operations, o) } } } return operations } // NewChannel creates a new Channel. Useful for testing. func NewChannel(path string) *Channel { return &Channel{ PathField: path, } } type Channel struct { Extendable Describable `mapstructure:",squash"` PathField string `mapstructure:"path" json:"path"` ParametersField map[string]ChannelParameter `mapstructure:"parameters" json:"parameters"` Subscribe *SubscribeOperation `mapstructure:"subscribe" json:"subscribe"` Publish *PublishOperation `mapstructure:"publish" json:"publish"` } func (c Channel) IDField() string { return "path" } func (c Channel) ID() string { return c.PathField } func (c Channel) Path() string { return c.PathField } func (c Channel) Parameters() []asyncapi.ChannelParameter { var parameters []asyncapi.ChannelParameter for _, p := range c.ParametersField { parameters = append(parameters, p) } return parameters } func (c Channel) HasParameters() bool { return len(c.ParametersField) > 0 } func (c Channel) Operations() []asyncapi.Operation { var operations []asyncapi.Operation if c.Publish != nil { operations = append(operations, c.Publish) } if c.Subscribe != nil { operations = append(operations, c.Subscribe) } return operations } func (c Channel) Messages() []asyncapi.Message { var messages []asyncapi.Message for _, o := range c.Operations() { messages = append(messages, o.Messages()...) } return messages } type ChannelParameter struct { Extendable Describable NameField string `mapstructure:"name"` SchemaField *Schema `mapstructure:"schema"` } func (c ChannelParameter) IDField() string { return "name" } func (c ChannelParameter) ID() string { return c.NameField } func (c ChannelParameter) Name() string { return c.NameField } func (c ChannelParameter) Schema() asyncapi.Schema { return c.SchemaField } type SubscribeOperation struct { Operation } // NewSubscribeOperation creates a new SubscribeOperation. Useful for testing. func NewSubscribeOperation(msgs ...*Message) *SubscribeOperation { return &SubscribeOperation{Operation: *NewOperation(OperationTypeSubscribe, msgs...)} } func (o SubscribeOperation) MapStructureDefaults() map[string]interface{} { return map[string]interface{}{ "operationType": OperationTypeSubscribe, } } // NewPublishOperation creates a new PublishOperation. Useful for testing. func NewPublishOperation(msgs ...*Message) *PublishOperation { return &PublishOperation{Operation: *NewOperation(OperationTypePublish, msgs...)} } type PublishOperation struct { Operation } func (o PublishOperation) MapStructureDefaults() map[string]interface{} { return map[string]interface{}{ "operationType": OperationTypePublish, } } // NewOperation creates a new Operation. Useful for testing. func NewOperation(operationType asyncapi.OperationType, msgs ...*Message) *Operation { op := &Operation{ OperationType: operationType, } if len(msgs) == 0 { return op } op.MessageField = *NewMessages(msgs) return op } type Operation struct { Extendable Describable `mapstructure:",squash"` OperationIDField string `mapstructure:"operationId" json:"operationId"` MessageField Messages `mapstructure:"message" json:"message"` OperationType asyncapi.OperationType `mapstructure:"operationType" json:"operationType"` // set by hook SummaryField string `mapstructure:"summary" json:"summary"` } func (o Operation) ID() string { return o.OperationIDField } func (o Operation) IsApplicationPublishing() bool { return o.Type() == OperationTypeSubscribe } func (o Operation) IsApplicationSubscribing() bool { return o.Type() == OperationTypePublish } func (o Operation) IsClientPublishing() bool { return o.Type() == OperationTypePublish } func (o Operation) IsClientSubscribing() bool { return o.Type() == OperationTypeSubscribe } func (o Operation) Messages() []asyncapi.Message { msgs := o.MessageField.Messages() convertedMsgs := make([]asyncapi.Message, len(msgs)) // Go lack of covariance :/ for i, m := range msgs { convertedMsgs[i] = m } return convertedMsgs } func (o Operation) Type() asyncapi.OperationType { return o.OperationType } func (o Operation) Summary() string { return o.SummaryField } func (o Operation) HasSummary() bool { return o.SummaryField != "" } // Messages is a variadic type for Message object, which can be either one message or oneOf. // See https://www.asyncapi.com/docs/specifications/v2.0.0#operationObject. type Messages struct { Message `mapstructure:",squash"` OneOfField []*Message `mapstructure:"oneOf" json:"oneOf"` } func (m *Messages) Messages() []*Message { if len(m.OneOfField) > 0 { return m.OneOfField } return []*Message{&m.Message} } // NewMessages creates Messages. func NewMessages(msgs []*Message) *Messages { if len(msgs) == 1 { return &Messages{Message: *msgs[0]} } return &Messages{OneOfField: msgs} } type Message struct { Extendable Describable `mapstructure:",squash"` NameField string `mapstructure:"name" json:"name"` TitleField string `mapstructure:"title" json:"title"` SummaryField string `mapstructure:"summary" json:"summary"` ContentTypeField string `mapstructure:"contentType" json:"contentType"` PayloadField *Schema `mapstructure:"payload" json:"payload"` } func (m Message) UID() string { return m.Name() } func (m Message) Name() string { return m.NameField } func (m Message) Title() string { return m.TitleField } func (m Message) HasTitle() bool { return m.TitleField != "" } func (m Message) Summary() string { return m.SummaryField } func (m Message) HasSummary() bool { return m.SummaryField != "" } func (m Message) ContentType() string { return m.ContentTypeField } func (m Message) Payload() asyncapi.Schema { return m.PayloadField } type Schemas map[string]*Schema func (s Schemas) ToInterface(dst map[string]asyncapi.Schema) map[string]asyncapi.Schema { if len(dst) > 0 { return dst } if dst == nil { dst = make(map[string]asyncapi.Schema) } for k, v := range s { dst[k] = v } return dst } type FalsifiableSchema struct { val interface{} } // NewFalsifiableSchema creates a new FalsifiableSchema. func NewFalsifiableSchema(val interface{}) *FalsifiableSchema { if val == nil { return nil } return &FalsifiableSchema{val: val} } func (f FalsifiableSchema) IsFalse() bool { _, ok := f.val.(bool) return ok } func (f FalsifiableSchema) IsSchema() bool { _, ok := f.val.(*Schema) return ok } func (f FalsifiableSchema) Schema() asyncapi.Schema { if f.IsSchema() { return f.val.(*Schema) } return nil } type Schema struct { Extendable AdditionalItemsField interface{} `mapstructure:"additionalItems" json:"additionalItems,omitempty"` AdditionalPropertiesField interface{} `mapstructure:"additionalProperties" json:"additionalProperties,omitempty"` // Schema || false AllOfField []asyncapi.Schema `mapstructure:"allOf" json:"allOf,omitempty"` AnyOfField []asyncapi.Schema `mapstructure:"anyOf" json:"anyOf,omitempty"` ConstField interface{} `mapstructure:"const" json:"const,omitempty"` ContainsField *Schema `mapstructure:"contains" json:"contains,omitempty"` ContentEncodingField string `mapstructure:"contentEncoding" json:"contentEncoding,omitempty"` ContentMediaTypeField string `mapstructure:"contentMediaType" json:"contentMediaType,omitempty"` DefaultField interface{} `mapstructure:"default" json:"default,omitempty"` DefinitionsField Schemas `mapstructure:"definitions" json:"definitions,omitempty"` DependenciesField Schemas `mapstructure:"dependencies" json:"dependencies,omitempty"` DeprecatedField bool `mapstructure:"deprecated" json:"deprecated,omitempty"` DescriptionField string `mapstructure:"description" json:"description,omitempty"` DiscriminatorField string `mapstructure:"discriminator" json:"discriminator,omitempty"` ElseField *Schema `mapstructure:"else" json:"else,omitempty"` EnumField []interface{} `mapstructure:"enum" json:"enum,omitempty"` ExamplesField []interface{} `mapstructure:"examples" json:"examples,omitempty"` ExclusiveMaximumField *float64 `mapstructure:"exclusiveMaximum" json:"exclusiveMaximum,omitempty"` ExclusiveMinimumField *float64 `mapstructure:"exclusiveMinimum" json:"exclusiveMinimum,omitempty"` FormatField string `mapstructure:"format" json:"format,omitempty"` IDField string `mapstructure:"$id" json:"$id,omitempty"` IfField *Schema `mapstructure:"if" json:"if,omitempty"` ItemsField []asyncapi.Schema `mapstructure:"items" json:"items,omitempty"` MaximumField *float64 `mapstructure:"maximum" json:"maximum,omitempty"` MaxItemsField *float64 `mapstructure:"maxItems" json:"maxItems,omitempty"` MaxLengthField *float64 `mapstructure:"maxLength" json:"maxLength,omitempty"` MaxPropertiesField *float64 `mapstructure:"maxProperties" json:"maxProperties,omitempty"` MinimumField *float64 `mapstructure:"minimum" json:"minimum,omitempty"` MinItemsField *float64 `mapstructure:"minItems" json:"minItems,omitempty"` MinLengthField *float64 `mapstructure:"minLength" json:"minLength,omitempty"` MinPropertiesField *float64 `mapstructure:"minProperties" json:"minProperties,omitempty"` MultipleOfField *float64 `mapstructure:"multipleOf" json:"multipleOf,omitempty"` NotField *Schema `mapstructure:"not" json:"not,omitempty"` OneOfField []asyncapi.Schema `mapstructure:"oneOf" json:"oneOf,omitempty"` PatternField string `mapstructure:"pattern" json:"pattern,omitempty"` PatternPropertiesField Schemas `mapstructure:"patternProperties" json:"patternProperties,omitempty"` PropertiesField Schemas `mapstructure:"properties" json:"properties,omitempty"` PropertyNamesField *Schema `mapstructure:"propertyNames" json:"propertyNames,omitempty"` ReadOnlyField bool `mapstructure:"readOnly" json:"readOnly,omitempty"` RequiredField []string `mapstructure:"required" json:"required,omitempty"` ThenField *Schema `mapstructure:"then" json:"then,omitempty"` TitleField string `mapstructure:"title" json:"title,omitempty"` TypeField interface{} `mapstructure:"type" json:"type,omitempty"` // string | []string UniqueItemsField bool `mapstructure:"uniqueItems" json:"uniqueItems,omitempty"` WriteOnlyField bool `mapstructure:"writeOnly" json:"writeOnly,omitempty"` // cached converted map[string]asyncapi.Schema from map[string]*Schema propertiesFieldMap map[string]asyncapi.Schema patternPropertiesFieldMap map[string]asyncapi.Schema definitionsFieldMap map[string]asyncapi.Schema dependenciesFieldMap map[string]asyncapi.Schema } func (s *Schema) AdditionalItems() asyncapi.FalsifiableSchema { return NewFalsifiableSchema(s.AdditionalItemsField) } func (s *Schema) AdditionalProperties() asyncapi.FalsifiableSchema { return NewFalsifiableSchema(s.AdditionalPropertiesField) } func (s *Schema) AllOf() []asyncapi.Schema { return s.AllOfField } func (s *Schema) AnyOf() []asyncapi.Schema { return s.AnyOfField } func (s *Schema) CircularProps() []string { if props, ok := s.Extension("x-parser-circular-props").([]string); ok { return props } return nil } func (s *Schema) Const() interface{} { return s.ConstField } func (s *Schema) Contains() asyncapi.Schema { return s.ContainsField } func (s *Schema) ContentEncoding() string { return s.ContentEncodingField } func (s *Schema) ContentMediaType() string { return s.ContentMediaTypeField } func (s *Schema) Default() interface{} { return s.DefaultField } func (s *Schema) Definitions() map[string]asyncapi.Schema { s.definitionsFieldMap = s.DefinitionsField.ToInterface(s.definitionsFieldMap) return s.definitionsFieldMap } func (s *Schema) Dependencies() map[string]asyncapi.Schema { s.dependenciesFieldMap = s.DependenciesField.ToInterface(s.dependenciesFieldMap) return s.dependenciesFieldMap } func (s *Schema) Deprecated() bool { return s.DeprecatedField } func (s *Schema) Description() string { return s.DescriptionField } func (s *Schema) Discriminator() string { return s.DiscriminatorField } func (s *Schema) Else() asyncapi.Schema { return s.ElseField } func (s *Schema) Enum() []interface{} { return s.EnumField } func (s *Schema) Examples() []interface{} { return s.ExamplesField } func (s *Schema) ExclusiveMaximum() *float64 { return s.ExclusiveMaximumField } func (s *Schema) ExclusiveMinimum() *float64 { return s.ExclusiveMinimumField } func (s *Schema) Format() string { return s.FormatField } func (s *Schema) HasCircularProps() bool { return len(s.CircularProps()) > 0 } func (s *Schema) ID() string { return s.IDField } func (s *Schema) If() asyncapi.Schema { return s.IfField } func (s *Schema) IsCircular() bool { if isCircular, ok := s.Extension("x-parser-circular").(bool); ok { return isCircular } return false } func (s *Schema) Items() []asyncapi.Schema { return s.ItemsField } func (s *Schema) Maximum() *float64 { return s.MaximumField } func (s *Schema) MaxItems() *float64 { return s.MaxItemsField } func (s *Schema) MaxLength() *float64 { return s.MaxLengthField } func (s *Schema) MaxProperties() *float64 { return s.MaxPropertiesField } func (s *Schema) Minimum() *float64 { return s.MinimumField } func (s *Schema) MinItems() *float64 { return s.MinItemsField } func (s *Schema) MinLength() *float64 { return s.MinLengthField } func (s *Schema) MinProperties() *float64 { return s.MinPropertiesField } func (s *Schema) MultipleOf() *float64 { return s.MultipleOfField } func (s *Schema) Not() asyncapi.Schema { return s.NotField } func (s *Schema) OneOf() []asyncapi.Schema { return s.OneOfField } func (s *Schema) Pattern() string { return s.PatternField } func (s *Schema) PatternProperties() map[string]asyncapi.Schema { s.patternPropertiesFieldMap = s.PatternPropertiesField.ToInterface(s.patternPropertiesFieldMap) return s.patternPropertiesFieldMap } func (s *Schema) Properties() map[string]asyncapi.Schema { s.propertiesFieldMap = s.PropertiesField.ToInterface(s.propertiesFieldMap) return s.propertiesFieldMap } func (s *Schema) Property(name string) asyncapi.Schema { return s.PropertiesField[name] } func (s *Schema) PropertyNames() asyncapi.Schema { return s.PropertyNamesField } func (s *Schema) ReadOnly() bool { return s.ReadOnlyField } func (s *Schema) Required() []string { return s.RequiredField } func (s *Schema) Then() asyncapi.Schema { return s.ThenField } func (s *Schema) Title() string { return s.TitleField } func (s *Schema) Type() []string { if stringVal, isString := s.TypeField.(string); isString { return []string{stringVal} } if sliceVal, isSlice := s.TypeField.([]string); isSlice { return sliceVal } return nil } func (s *Schema) UID() string { if id := s.ID(); id != "" { return id } // This is not yet supported by parser-go parserGeneratedID, ok := s.Extension("x-parser-id").(string) if ok { return parserGeneratedID } return "" } func (s *Schema) UniqueItems() bool { return s.UniqueItemsField } func (s *Schema) WriteOnly() bool { return s.WriteOnlyField } type Server struct { Extendable Describable `mapstructure:",squash"` NameField string `mapstructure:"name" json:"name"` ProtocolField string `mapstructure:"protocol" json:"protocol"` URLField string `mapstructure:"url" json:"url"` VariablesField map[string]ServerVariable `mapstructure:"variables" json:"variables"` } func (s Server) Variables() []asyncapi.ServerVariable { var vars []asyncapi.ServerVariable for _, v := range s.VariablesField { vars = append(vars, v) } return vars } func (s Server) IDField() string { return "name" } func (s Server) ID() string { return s.NameField } func (s Server) Name() string { return s.NameField } func (s Server) HasName() bool { return s.NameField != "" } func (s Server) URL() string { return s.URLField } func (s Server) HasURL() bool { return s.URLField != "" } func (s Server) Protocol() string { return s.ProtocolField } func (s Server) HasProtocol() bool { return s.ProtocolField != "" } type ServerVariable struct { Extendable NameField string `mapstructure:"name" json:"name"` Default string `mapstructure:"default" json:"default"` Enum []string `mapstructure:"enum" json:"enum"` } func (s ServerVariable) IDField() string { return "name" } func (s ServerVariable) ID() string { return s.NameField } func (s ServerVariable) Name() string { return s.NameField } func (s ServerVariable) HasName() bool { return s.NameField != "" } func (s ServerVariable) DefaultValue() string { return s.Default } func (s ServerVariable) AllowedValues() []string { return s.Enum } type Describable struct { DescriptionField string `mapstructure:"description" json:"description"` } func (d Describable) Description() string { return d.DescriptionField } func (d Describable) HasDescription() bool { return d.DescriptionField != "" } type Extendable struct { Raw map[string]interface{} `mapstructure:",remain" json:"-"` } func (e Extendable) HasExtension(name string) bool { _, ok := e.Raw[name] return ok } func (e Extendable) Extension(name string) interface{} { return e.Raw[name] }