mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
feat: add attribute to schema model
This commit is contained in:
committed by
Dave Shanley
parent
4c331de207
commit
99bf12c1c7
@@ -5,9 +5,10 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
@@ -68,6 +69,9 @@ type Schema struct {
|
|||||||
// in 3.1 Items can be a Schema or a boolean
|
// in 3.1 Items can be a Schema or a boolean
|
||||||
Items *DynamicValue[*SchemaProxy, bool] `json:"items,omitempty" yaml:"items,omitempty"`
|
Items *DynamicValue[*SchemaProxy, bool] `json:"items,omitempty" yaml:"items,omitempty"`
|
||||||
|
|
||||||
|
// 3.1 only, part of the JSON Schema spec provides a way to identify a subschema
|
||||||
|
Anchor string `json:"$anchor,omitempty" yaml:"$anchor,omitempty"`
|
||||||
|
|
||||||
// Compatible with all versions
|
// Compatible with all versions
|
||||||
Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"`
|
Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"`
|
||||||
Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"`
|
Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"`
|
||||||
@@ -77,26 +81,26 @@ type Schema struct {
|
|||||||
Minimum *int64 `json:"minimum,omitempty" yaml:"minimum,omitempty"`
|
Minimum *int64 `json:"minimum,omitempty" yaml:"minimum,omitempty"`
|
||||||
MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
|
MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
|
||||||
MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
|
MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
|
||||||
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
|
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
|
||||||
Format string `json:"format,omitempty" yaml:"format,omitempty"`
|
Format string `json:"format,omitempty" yaml:"format,omitempty"`
|
||||||
MaxItems *int64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
|
MaxItems *int64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
|
||||||
MinItems *int64 `json:"minItems,omitempty" yaml:"minItems,omitempty"`
|
MinItems *int64 `json:"minItems,omitempty" yaml:"minItems,omitempty"`
|
||||||
UniqueItems *int64 `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
|
UniqueItems *int64 `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
|
||||||
MaxProperties *int64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
MaxProperties *int64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
||||||
MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
||||||
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
||||||
Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"`
|
Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||||
AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,renderZero,omitempty"`
|
AdditionalProperties any `json:"additionalProperties,omitempty" yaml:"additionalProperties,renderZero,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Default any `json:"default,omitempty" yaml:"default,renderZero,omitempty"`
|
Default any `json:"default,omitempty" yaml:"default,renderZero,omitempty"`
|
||||||
Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
||||||
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
||||||
WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
||||||
XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"`
|
XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"`
|
||||||
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||||
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions map[string]any `json:"-" yaml:"-"`
|
||||||
low *base.Schema
|
low *base.Schema
|
||||||
|
|
||||||
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
||||||
@@ -282,6 +286,10 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
}
|
}
|
||||||
s.Enum = enum
|
s.Enum = enum
|
||||||
|
|
||||||
|
if !schema.Anchor.IsEmpty() {
|
||||||
|
s.Anchor = schema.Anchor.Value
|
||||||
|
}
|
||||||
|
|
||||||
// async work.
|
// async work.
|
||||||
// any polymorphic properties need to be handled in their own threads
|
// any polymorphic properties need to be handled in their own threads
|
||||||
// any properties each need to be processed in their own thread.
|
// any properties each need to be processed in their own thread.
|
||||||
|
|||||||
@@ -266,7 +266,8 @@ minLength: 1
|
|||||||
maxItems: 20
|
maxItems: 20
|
||||||
minItems: 10
|
minItems: 10
|
||||||
maxProperties: 30
|
maxProperties: 30
|
||||||
minProperties: 1`
|
minProperties: 1
|
||||||
|
$anchor: anchor`
|
||||||
|
|
||||||
var compNode yaml.Node
|
var compNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
_ = yaml.Unmarshal([]byte(testSpec), &compNode)
|
||||||
@@ -310,6 +311,7 @@ minProperties: 1`
|
|||||||
assert.True(t, compiled.WriteOnly)
|
assert.True(t, compiled.WriteOnly)
|
||||||
assert.True(t, *compiled.Deprecated)
|
assert.True(t, *compiled.Deprecated)
|
||||||
assert.True(t, *compiled.Nullable)
|
assert.True(t, *compiled.Nullable)
|
||||||
|
assert.Equal(t, "anchor", compiled.Anchor)
|
||||||
|
|
||||||
wentLow := compiled.GoLow()
|
wentLow := compiled.GoLow()
|
||||||
assert.Equal(t, 129, wentLow.AdditionalProperties.ValueNode.Line)
|
assert.Equal(t, 129, wentLow.AdditionalProperties.ValueNode.Line)
|
||||||
@@ -317,8 +319,7 @@ minProperties: 1`
|
|||||||
|
|
||||||
// now render it out!
|
// now render it out!
|
||||||
schemaBytes, _ := compiled.Render()
|
schemaBytes, _ := compiled.Render()
|
||||||
assert.Len(t, schemaBytes, 3460)
|
assert.Len(t, schemaBytes, 3476)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaObjectWithAllOfSequenceOrder(t *testing.T) {
|
func TestSchemaObjectWithAllOfSequenceOrder(t *testing.T) {
|
||||||
|
|||||||
@@ -39,15 +39,16 @@ const (
|
|||||||
OneOfLabel = "oneOf"
|
OneOfLabel = "oneOf"
|
||||||
NotLabel = "not"
|
NotLabel = "not"
|
||||||
TypeLabel = "type"
|
TypeLabel = "type"
|
||||||
DiscriminatorLabel = "discriminator"
|
DiscriminatorLabel = "discriminator"
|
||||||
ExclusiveMinimumLabel = "exclusiveMinimum"
|
ExclusiveMinimumLabel = "exclusiveMinimum"
|
||||||
ExclusiveMaximumLabel = "exclusiveMaximum"
|
ExclusiveMaximumLabel = "exclusiveMaximum"
|
||||||
SchemaLabel = "schema"
|
SchemaLabel = "schema"
|
||||||
SchemaTypeLabel = "$schema"
|
SchemaTypeLabel = "$schema"
|
||||||
|
AnchorLabel = "$anchor"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PropertyNames low.NodeReference[*SchemaProxy]
|
PropertyNames low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedProperties low.NodeReference[*SchemaProxy]
|
UnevaluatedProperties low.NodeReference[*SchemaProxy]
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ type Schema struct {
|
|||||||
PropertyNames low.NodeReference[*SchemaProxy]
|
PropertyNames low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedProperties low.NodeReference[*SchemaProxy]
|
UnevaluatedProperties low.NodeReference[*SchemaProxy]
|
||||||
|
Anchor low.NodeReference[string]
|
||||||
|
|
||||||
// Compatible with all versions
|
// Compatible with all versions
|
||||||
Title low.NodeReference[string]
|
Title low.NodeReference[string]
|
||||||
@@ -394,6 +395,9 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
if !s.UnevaluatedItems.IsEmpty() {
|
if !s.UnevaluatedItems.IsEmpty() {
|
||||||
d = append(d, low.GenerateHashString(s.UnevaluatedItems.Value))
|
d = append(d, low.GenerateHashString(s.UnevaluatedItems.Value))
|
||||||
}
|
}
|
||||||
|
if !s.Anchor.IsEmpty() {
|
||||||
|
d = append(d, fmt.Sprint(s.Anchor.Value))
|
||||||
|
}
|
||||||
|
|
||||||
depSchemasKeys := make([]string, len(s.DependentSchemas.Value))
|
depSchemasKeys := make([]string, len(s.DependentSchemas.Value))
|
||||||
z = 0
|
z = 0
|
||||||
@@ -514,6 +518,7 @@ func (s *Schema) GetExtensions() map[low.KeyReference[string]]low.ValueReference
|
|||||||
// - PropertyNames
|
// - PropertyNames
|
||||||
// - UnevaluatedItems
|
// - UnevaluatedItems
|
||||||
// - UnevaluatedProperties
|
// - UnevaluatedProperties
|
||||||
|
// - Anchor
|
||||||
func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
s.Reference = new(low.Reference)
|
s.Reference = new(low.Reference)
|
||||||
if h, _, _ := utils.IsNodeRefValue(root); h {
|
if h, _, _ := utils.IsNodeRefValue(root); h {
|
||||||
@@ -615,6 +620,14 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle anchor if set. (3.1)
|
||||||
|
_, anchorLabel, anchorNode := utils.FindKeyNodeFullTop(AnchorLabel, root.Content)
|
||||||
|
if anchorNode != nil {
|
||||||
|
s.Anchor = low.NodeReference[string]{
|
||||||
|
Value: anchorNode.Value, KeyNode: anchorLabel, ValueNode: anchorLabel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handle example if set. (3.0)
|
// handle example if set. (3.0)
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ examples:
|
|||||||
contains:
|
contains:
|
||||||
type: int
|
type: int
|
||||||
maxContains: 10
|
maxContains: 10
|
||||||
minContains: 1`
|
minContains: 1
|
||||||
|
$anchor: anchor`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Schema(t *testing.T) {
|
func Test_Schema(t *testing.T) {
|
||||||
@@ -308,6 +309,7 @@ func Test_Schema(t *testing.T) {
|
|||||||
assert.Equal(t, "string", sch.PropertyNames.Value.Schema().Type.Value.A)
|
assert.Equal(t, "string", sch.PropertyNames.Value.Schema().Type.Value.A)
|
||||||
assert.Equal(t, "boolean", sch.UnevaluatedItems.Value.Schema().Type.Value.A)
|
assert.Equal(t, "boolean", sch.UnevaluatedItems.Value.Schema().Type.Value.A)
|
||||||
assert.Equal(t, "integer", sch.UnevaluatedProperties.Value.Schema().Type.Value.A)
|
assert.Equal(t, "integer", sch.UnevaluatedProperties.Value.Schema().Type.Value.A)
|
||||||
|
assert.Equal(t, "anchor", sch.Anchor.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaAllOfSequenceOrder(t *testing.T) {
|
func TestSchemaAllOfSequenceOrder(t *testing.T) {
|
||||||
|
|||||||
@@ -5,86 +5,86 @@ package v3
|
|||||||
|
|
||||||
// Label definitions used to look up vales in yaml.Node tree.
|
// Label definitions used to look up vales in yaml.Node tree.
|
||||||
const (
|
const (
|
||||||
ComponentsLabel = "components"
|
ComponentsLabel = "components"
|
||||||
SchemasLabel = "schemas"
|
SchemasLabel = "schemas"
|
||||||
EncodingLabel = "encoding"
|
EncodingLabel = "encoding"
|
||||||
HeadersLabel = "headers"
|
HeadersLabel = "headers"
|
||||||
ExpressionLabel = "expression"
|
ExpressionLabel = "expression"
|
||||||
InfoLabel = "info"
|
InfoLabel = "info"
|
||||||
SwaggerLabel = "swagger"
|
SwaggerLabel = "swagger"
|
||||||
ParametersLabel = "parameters"
|
ParametersLabel = "parameters"
|
||||||
RequestBodyLabel = "requestBody"
|
RequestBodyLabel = "requestBody"
|
||||||
RequestBodiesLabel = "requestBodies"
|
RequestBodiesLabel = "requestBodies"
|
||||||
ResponsesLabel = "responses"
|
ResponsesLabel = "responses"
|
||||||
CallbacksLabel = "callbacks"
|
CallbacksLabel = "callbacks"
|
||||||
ContentLabel = "content"
|
ContentLabel = "content"
|
||||||
PathsLabel = "paths"
|
PathsLabel = "paths"
|
||||||
PathLabel = "path"
|
PathLabel = "path"
|
||||||
WebhooksLabel = "webhooks"
|
WebhooksLabel = "webhooks"
|
||||||
JSONSchemaDialectLabel = "jsonSchemaDialect"
|
JSONSchemaDialectLabel = "jsonSchemaDialect"
|
||||||
JSONSchemaLabel = "$schema"
|
JSONSchemaLabel = "$schema"
|
||||||
GetLabel = "get"
|
GetLabel = "get"
|
||||||
PostLabel = "post"
|
PostLabel = "post"
|
||||||
PatchLabel = "patch"
|
PatchLabel = "patch"
|
||||||
PutLabel = "put"
|
PutLabel = "put"
|
||||||
DeleteLabel = "delete"
|
DeleteLabel = "delete"
|
||||||
OptionsLabel = "options"
|
OptionsLabel = "options"
|
||||||
HeadLabel = "head"
|
HeadLabel = "head"
|
||||||
TraceLabel = "trace"
|
TraceLabel = "trace"
|
||||||
LinksLabel = "links"
|
LinksLabel = "links"
|
||||||
DefaultLabel = "default"
|
DefaultLabel = "default"
|
||||||
SecurityLabel = "security"
|
SecurityLabel = "security"
|
||||||
SecuritySchemesLabel = "securitySchemes"
|
SecuritySchemesLabel = "securitySchemes"
|
||||||
OAuthFlowsLabel = "flows"
|
OAuthFlowsLabel = "flows"
|
||||||
VariablesLabel = "variables"
|
VariablesLabel = "variables"
|
||||||
ServersLabel = "servers"
|
ServersLabel = "servers"
|
||||||
ServerLabel = "server"
|
ServerLabel = "server"
|
||||||
ImplicitLabel = "implicit"
|
ImplicitLabel = "implicit"
|
||||||
PasswordLabel = "password"
|
PasswordLabel = "password"
|
||||||
ClientCredentialsLabel = "clientCredentials"
|
ClientCredentialsLabel = "clientCredentials"
|
||||||
AuthorizationCodeLabel = "authorizationCode"
|
AuthorizationCodeLabel = "authorizationCode"
|
||||||
DescriptionLabel = "description"
|
DescriptionLabel = "description"
|
||||||
URLLabel = "url"
|
URLLabel = "url"
|
||||||
NameLabel = "name"
|
NameLabel = "name"
|
||||||
EmailLabel = "email"
|
EmailLabel = "email"
|
||||||
TitleLabel = "title"
|
TitleLabel = "title"
|
||||||
TermsOfServiceLabel = "termsOfService"
|
TermsOfServiceLabel = "termsOfService"
|
||||||
VersionLabel = "version"
|
VersionLabel = "version"
|
||||||
OpenAPILabel = "openapi"
|
OpenAPILabel = "openapi"
|
||||||
HostLabel = "host"
|
HostLabel = "host"
|
||||||
BasePathLabel = "basePath"
|
BasePathLabel = "basePath"
|
||||||
LicenseLabel = "license"
|
LicenseLabel = "license"
|
||||||
ContactLabel = "contact"
|
ContactLabel = "contact"
|
||||||
NamespaceLabel = "namespace"
|
NamespaceLabel = "namespace"
|
||||||
PrefixLabel = "prefix"
|
PrefixLabel = "prefix"
|
||||||
AttributeLabel = "attribute"
|
AttributeLabel = "attribute"
|
||||||
WrappedLabel = "wrapped"
|
WrappedLabel = "wrapped"
|
||||||
PropertyNameLabel = "propertyName"
|
PropertyNameLabel = "propertyName"
|
||||||
SummaryLabel = "summary"
|
SummaryLabel = "summary"
|
||||||
ValueLabel = "value"
|
ValueLabel = "value"
|
||||||
ExternalValue = "externalValue"
|
ExternalValue = "externalValue"
|
||||||
SchemaDialectLabel = "$schema"
|
SchemaDialectLabel = "$schema"
|
||||||
ExclusiveMaximumLabel = "exclusiveMaximum"
|
ExclusiveMaximumLabel = "exclusiveMaximum"
|
||||||
ExclusiveMinimumLabel = "exclusiveMinimum"
|
ExclusiveMinimumLabel = "exclusiveMinimum"
|
||||||
TypeLabel = "type"
|
TypeLabel = "type"
|
||||||
TagsLabel = "tags"
|
TagsLabel = "tags"
|
||||||
MultipleOfLabel = "multipleOf"
|
MultipleOfLabel = "multipleOf"
|
||||||
MaximumLabel = "maximum"
|
MaximumLabel = "maximum"
|
||||||
MinimumLabel = "minimum"
|
MinimumLabel = "minimum"
|
||||||
MaxLengthLabel = "maxLength"
|
MaxLengthLabel = "maxLength"
|
||||||
MinLengthLabel = "minLength"
|
MinLengthLabel = "minLength"
|
||||||
PatternLabel = "pattern"
|
PatternLabel = "pattern"
|
||||||
FormatLabel = "format"
|
FormatLabel = "format"
|
||||||
MaxItemsLabel = "maxItems"
|
MaxItemsLabel = "maxItems"
|
||||||
ExamplesLabel = "examples"
|
ExamplesLabel = "examples"
|
||||||
MinItemsLabel = "minItems"
|
MinItemsLabel = "minItems"
|
||||||
UniqueItemsLabel = "uniqueItems"
|
UniqueItemsLabel = "uniqueItems"
|
||||||
MaxPropertiesLabel = "maxProperties"
|
MaxPropertiesLabel = "maxProperties"
|
||||||
MinPropertiesLabel = "minProperties"
|
MinPropertiesLabel = "minProperties"
|
||||||
RequiredLabel = "required"
|
RequiredLabel = "required"
|
||||||
EnumLabel = "enum"
|
EnumLabel = "enum"
|
||||||
SchemaLabel = "schema"
|
SchemaLabel = "schema"
|
||||||
NotLabel = "not"
|
NotLabel = "not"
|
||||||
ItemsLabel = "items"
|
ItemsLabel = "items"
|
||||||
PropertiesLabel = "properties"
|
PropertiesLabel = "properties"
|
||||||
AllOfLabel = "allOf"
|
AllOfLabel = "allOf"
|
||||||
@@ -136,4 +136,5 @@ const (
|
|||||||
UnevaluatedPropertiesLabel = "unevaluatedProperties"
|
UnevaluatedPropertiesLabel = "unevaluatedProperties"
|
||||||
DependentSchemasLabel = "dependentSchemas"
|
DependentSchemasLabel = "dependentSchemas"
|
||||||
PatternPropertiesLabel = "patternProperties"
|
PatternPropertiesLabel = "patternProperties"
|
||||||
|
AnchorLabel = "$anchor"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user