@@ -117,38 +117,32 @@ func (ps *tagBaseFieldParserV3) CustomSchema() (*spec.RefOrSpec[spec.Schema], er
117117
118118// ComplementSchema complement schema with field properties
119119func (ps * tagBaseFieldParserV3 ) ComplementSchema (schema * spec.RefOrSpec [spec.Schema ]) error {
120- if schema .Spec == nil {
121- componentSchema := ps .p .openAPI .Components .Spec .Schemas [strings .ReplaceAll (schema .Ref .Ref , "#/components/schemas/" , "" )]
122- if componentSchema == nil {
123- return fmt .Errorf ("could not resolve schema for ref %s" , schema .Ref .Ref )
124- }
125- schema = componentSchema
126- }
127-
128120 types := ps .p .GetSchemaTypePathV3 (schema , 2 )
129121 if len (types ) == 0 {
130122 return fmt .Errorf ("invalid type for field: %s" , ps .field .Names [0 ])
131123 }
132124
133125 if schema .Ref != nil { //IsRefSchema(schema)
134- // TODO fetch existing schema from components
135126 var newSchema = spec.Schema {}
136- err := ps .complementSchema (& newSchema , types )
127+ err := ps .complementSchema (& newSchema , types , ps . p . getSchemaByRef ( schema . Ref ) )
137128 if err != nil {
138129 return err
139130 }
140131 if ! reflect .ValueOf (newSchema ).IsZero () {
141- newSchema .AllOf = []* spec.RefOrSpec [spec.Schema ]{{Spec : schema .Spec }}
132+ if newSchema .Extensions == nil {
133+ newSchema .Extensions = make (map [string ]any )
134+ }
135+ newSchema .Extensions ["$ref" ] = schema .Ref .Ref
142136 * schema = spec.RefOrSpec [spec.Schema ]{Spec : & newSchema }
143137 }
144138 return nil
145139 }
146140
147- return ps .complementSchema (schema .Spec , types )
141+ return ps .complementSchema (schema .Spec , types , nil )
148142}
149143
150144// complementSchema complement schema with field properties
151- func (ps * tagBaseFieldParserV3 ) complementSchema (schema * spec.Schema , types []string ) error {
145+ func (ps * tagBaseFieldParserV3 ) complementSchema (schema * spec.Schema , types []string , refSchema * spec. Schema ) error {
152146 if ps .field .Tag == nil {
153147 if ps .field .Doc != nil {
154148 schema .Description = strings .TrimSpace (ps .field .Doc .Text ())
@@ -357,16 +351,22 @@ func (ps *tagBaseFieldParserV3) complementSchema(schema *spec.Schema, types []st
357351 }
358352
359353 elemSchema := schema
354+ elemRefSchema := refSchema
355+ var itemRef * spec.Ref
360356
361357 if field .schemaType == ARRAY {
362358 // For Array only
363359 schema .MaxItems = field .maxItems
364360 schema .MinItems = field .minItems
365361 schema .UniqueItems = & field .unique
366362
367- elemSchema = schema .Items .Schema .Spec
368- if elemSchema == nil {
369- elemSchema = ps .p .getSchemaByRef (schema .Items .Schema .Ref )
363+ if schema .Items .Schema .Ref != nil {
364+ itemRef = schema .Items .Schema .Ref
365+ elemSchema = & spec.Schema {}
366+ elemRefSchema = ps .p .getSchemaByRef (itemRef )
367+ } else {
368+ elemSchema = schema .Items .Schema .Spec
369+ elemRefSchema = nil
370370 }
371371
372372 elemSchema .Format = field .formatType
@@ -377,13 +377,57 @@ func (ps *tagBaseFieldParserV3) complementSchema(schema *spec.Schema, types []st
377377 elemSchema .MultipleOf = field .multipleOf
378378 elemSchema .MaxLength = field .maxLength
379379 elemSchema .MinLength = field .minLength
380- elemSchema .Enum = append (elemSchema .Enum , field .enums ... )
380+ if shouldApplyFieldEnumConstraint (field .enums , elemRefSchema ) {
381+ elemSchema .Enum = append (elemSchema .Enum , field .enums ... )
382+ }
381383 elemSchema .Pattern = field .pattern
382384 elemSchema .OneOf = oneOfSchemas
383385
386+ if itemRef != nil && ! reflect .ValueOf (* elemSchema ).IsZero () {
387+ if elemSchema .Extensions == nil {
388+ elemSchema .Extensions = make (map [string ]any )
389+ }
390+ elemSchema .Extensions ["$ref" ] = itemRef .Ref
391+ schema .Items .Schema = spec .NewRefOrSpec [spec.Schema ](nil , elemSchema )
392+ }
393+
384394 return nil
385395}
386396
397+ func shouldApplyFieldEnumConstraint (fieldEnums []interface {}, refSchema * spec.Schema ) bool {
398+ if len (fieldEnums ) == 0 {
399+ return false
400+ }
401+
402+ if refSchema == nil || len (refSchema .Enum ) == 0 {
403+ return true
404+ }
405+
406+ if len (fieldEnums ) != len (refSchema .Enum ) {
407+ return true
408+ }
409+
410+ used := make ([]bool , len (refSchema .Enum ))
411+ for _ , fieldEnum := range fieldEnums {
412+ matched := false
413+ for i , refEnum := range refSchema .Enum {
414+ if used [i ] {
415+ continue
416+ }
417+ if reflect .DeepEqual (fieldEnum , refEnum ) {
418+ used [i ] = true
419+ matched = true
420+ break
421+ }
422+ }
423+ if ! matched {
424+ return true
425+ }
426+ }
427+
428+ return false
429+ }
430+
387431func getIntTagV3 (structTag reflect.StructTag , tagName string ) (* int , error ) {
388432 strValue := structTag .Get (tagName )
389433 if strValue == "" {
0 commit comments