11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT license.
33
4- using Microsoft . OpenApi . Any ;
54using Microsoft . OpenApi . Models ;
65using Microsoft . OpenApi . Properties ;
76using System . Collections . Generic ;
@@ -11,7 +10,6 @@ namespace Microsoft.OpenApi.Validations.Rules
1110 /// <summary>
1211 /// The validation rules for <see cref="OpenApiSchema"/>.
1312 /// </summary>
14-
1513 [ OpenApiRule ]
1614 public static class OpenApiSchemaRules
1715 {
@@ -70,15 +68,74 @@ public static class OpenApiSchemaRules
7068
7169 if ( schema . Reference != null && schema . Discriminator != null )
7270 {
73- if ( ! schema . Required . Contains ( schema . Discriminator ? . PropertyName ) )
71+ var discriminatorName = schema . Discriminator ? . PropertyName ;
72+
73+ if ( ! ValidateChildSchemaAgainstDiscriminator ( schema , discriminatorName ) )
7474 {
7575 context . CreateError ( nameof ( ValidateSchemaDiscriminator ) ,
76- string . Format ( SRResource . Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator ,
77- schema . Reference . Id , schema . Discriminator . PropertyName ) ) ;
76+ string . Format ( SRResource . Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator ,
77+ schema . Reference . Id , discriminatorName ) ) ;
7878 }
7979 }
8080
8181 context . Exit ( ) ;
8282 } ) ;
83+
84+ /// <summary>
85+ /// Validates the property name in the discriminator against the ones present in the children schema
86+ /// </summary>
87+ /// <param name="schema">The parent schema.</param>
88+ /// <param name="discriminatorName">Adds support for polymorphism. The discriminator is an object name that is used to differentiate
89+ /// between other schemas which may satisfy the payload description.</param>
90+ public static bool ValidateChildSchemaAgainstDiscriminator ( OpenApiSchema schema , string discriminatorName )
91+ {
92+ if ( ! schema . Required ? . Contains ( discriminatorName ) ?? false )
93+ {
94+ // recursively check nested schema.OneOf, schema.AnyOf or schema.AllOf and their required fields for the discriminator
95+ if ( schema . OneOf . Count != 0 )
96+ {
97+ return TraverseSchemaElements ( discriminatorName , schema . OneOf ) ;
98+ }
99+ if ( schema . AnyOf . Count != 0 )
100+ {
101+ return TraverseSchemaElements ( discriminatorName , schema . AnyOf ) ;
102+ }
103+ if ( schema . AllOf . Count != 0 )
104+ {
105+ return TraverseSchemaElements ( discriminatorName , schema . AllOf ) ;
106+ }
107+ }
108+ else
109+ {
110+ return true ;
111+ }
112+
113+ return false ;
114+ }
115+
116+ /// <summary>
117+ /// Traverses the schema elements and checks whether the schema contains the discriminator.
118+ /// </summary>
119+ /// <param name="discriminatorName">Adds support for polymorphism. The discriminator is an object name that is used to differentiate
120+ /// between other schemas which may satisfy the payload description.</param>
121+ /// <param name="childSchema">The child schema.</param>
122+ /// <returns></returns>
123+ public static bool TraverseSchemaElements ( string discriminatorName , IList < OpenApiSchema > childSchema )
124+ {
125+ foreach ( var childItem in childSchema )
126+ {
127+ if ( ( ! childItem . Properties ? . ContainsKey ( discriminatorName ) ?? false ) &&
128+ ( ! childItem . Required ? . Contains ( discriminatorName ) ?? false ) )
129+ {
130+ return ValidateChildSchemaAgainstDiscriminator ( childItem , discriminatorName ) ;
131+ }
132+ else
133+ {
134+ return true ;
135+ }
136+ }
137+
138+ return false ;
139+ }
83140 }
84141}
0 commit comments