Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# User-specific files (AI)
.claude/

# Mono auto generated files
mono_crash.*

Expand Down
26 changes: 22 additions & 4 deletions src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,10 @@ private static IEnumerable<KeyValuePair<string, string>> GetDiscriminatorMapping
// This avoids O(n²) expansion when a base type has a large discriminator mapping.
// For regular inheritance (lookupKeyInParentMapping=false), fall through to the
// inheritance-index path which returns subtypes without the O(n²) expansion.
// We search the full allOf ancestry chain (not just the immediate parent) because the
// discriminator may be defined on a grandparent schema (e.g. entity → directoryObject → application).
if (lookupKeyInParentMapping
&& schema.AllOf?.OfType<OpenApiSchemaReference>()
.Select(static x => x.RecursiveTarget)
.OfType<OpenApiSchema>()
.FirstOrDefault(allOfEvaluatorForMappings) is { } allOfRefTarget
&& FindAncestorSchemaWithDiscriminatorMapping(schema) is { } allOfRefTarget
&& schema.GetReferenceId() is string currentRefId
&& !string.IsNullOrEmpty(currentRefId))
{
Expand All @@ -462,6 +461,25 @@ private static IEnumerable<KeyValuePair<string, string>> GetDiscriminatorMapping
.Select(static x => KeyValuePair.Create(x.Key, x.Value.Reference.Id!));
}
private static readonly Func<IOpenApiSchema, bool> allOfEvaluatorForMappings = static x => x.Discriminator?.Mapping is { Count: > 0 };
/// <summary>
/// Recursively searches the allOf reference chain for the first ancestor schema that has a non-empty discriminator mapping.
/// This handles multi-level inheritance where the discriminator lives on a grandparent (or higher) schema,
/// not the immediate allOf parent.
/// </summary>
private static OpenApiSchema? FindAncestorSchemaWithDiscriminatorMapping(IOpenApiSchema schema, HashSet<IOpenApiSchema>? visited = null)
{
if (schema is null) return null;
visited ??= [];
foreach (var allOfRef in schema.AllOf?.OfType<OpenApiSchemaReference>() ?? [])
{
if (allOfRef.RecursiveTarget is not OpenApiSchema target || !visited.Add(target)) continue;
if (allOfEvaluatorForMappings(target))
return target;
var ancestor = FindAncestorSchemaWithDiscriminatorMapping(target, visited);
if (ancestor is not null) return ancestor;
}
return null;
}
private static IEnumerable<string> GetAllInheritanceSchemaReferences(string currentReferenceId, ConcurrentDictionary<string, ConcurrentDictionary<string, bool>> inheritanceIndex)
{
ArgumentException.ThrowIfNullOrEmpty(currentReferenceId);
Expand Down
Loading
Loading