Skip to content

Commit

Permalink
fix any/oneOf selection for plugins generation
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Biret <[email protected]>
  • Loading branch information
baywet committed Nov 27, 2024
1 parent 7e43820 commit 72d00e5
Showing 1 changed file with 91 additions and 36 deletions.
127 changes: 91 additions & 36 deletions src/Kiota.Builder/Plugins/PluginsGenerationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Kiota.Builder.OpenApiExtensions;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.ApiManifest;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Writers;
Expand Down Expand Up @@ -60,10 +61,10 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de
#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
var descriptionWriter = new OpenApiYamlWriter(fileWriter);
var trimmedPluginDocument = GetDocumentWithTrimmedComponentsAndResponses(OAIDocument);
trimmedPluginDocument = InlineRequestBodyAllOf(trimmedPluginDocument);
PrepareDescriptionForCopilot(trimmedPluginDocument);
// trimming a second time to remove any components that are no longer used after the inlining
trimmedPluginDocument = GetDocumentWithTrimmedComponentsAndResponses(trimmedPluginDocument);
trimmedPluginDocument.Info.Title = trimmedPluginDocument.Info.Title[..^9]; // removing the second ` - Subset` suffix from the title
trimmedPluginDocument.SerializeAsV3(descriptionWriter);
descriptionWriter.Flush();

Expand Down Expand Up @@ -144,8 +145,97 @@ private static IEnumerable<KeyValuePair<string, OpenApiSchema>> GetAllProperties
}
}

private sealed class SelectFirstAnyOneOfVisitor : OpenApiVisitorBase
{
public override void Visit(OpenApiSchema schema)
{
if (schema.AnyOf is { Count: > 0 })
{
CopyRelevantInformation(schema.AnyOf[0], schema);
schema.AnyOf.Clear();
}
if (schema.OneOf is { Count: > 0 })
{
CopyRelevantInformation(schema.OneOf[0], schema);
schema.OneOf.Clear();
}
base.Visit(schema);
}
private static void CopyRelevantInformation(OpenApiSchema source, OpenApiSchema target)
{
if (!string.IsNullOrEmpty(source.Type))
target.Type = source.Type;
if (!string.IsNullOrEmpty(source.Format))
target.Format = source.Format;
if (source.Items is not null)
target.Items = source.Items;
if (source.Properties is not null)
target.Properties = new Dictionary<string, OpenApiSchema>(source.Properties);
if (source.Required is not null)
target.Required = new HashSet<string>(source.Required);
if (source.AdditionalProperties is not null)
target.AdditionalProperties = source.AdditionalProperties;
if (source.Enum is not null)
target.Enum = [.. source.Enum];
if (source.ExclusiveMaximum is not null)
target.ExclusiveMaximum = source.ExclusiveMaximum;
if (source.ExclusiveMinimum is not null)
target.ExclusiveMinimum = source.ExclusiveMinimum;
if (source.Maximum is not null)
target.Maximum = source.Maximum;
if (source.Minimum is not null)
target.Minimum = source.Minimum;
if (source.MaxItems is not null)
target.MaxItems = source.MaxItems;
if (source.MinItems is not null)
target.MinItems = source.MinItems;
if (source.MaxLength is not null)
target.MaxLength = source.MaxLength;
if (source.MinLength is not null)
target.MinLength = source.MinLength;
if (source.Pattern is not null)
target.Pattern = source.Pattern;
if (source.MaxProperties is not null)
target.MaxProperties = source.MaxProperties;
if (source.MinProperties is not null)
target.MinProperties = source.MinProperties;
if (source.UniqueItems is not null)
target.UniqueItems = source.UniqueItems;
if (source.Nullable)
target.Nullable = true;
if (source.ReadOnly)
target.ReadOnly = true;
if (source.WriteOnly)
target.WriteOnly = true;
if (source.Deprecated)
target.Deprecated = true;
if (source.Xml is not null)
target.Xml = source.Xml;
if (source.ExternalDocs is not null)
target.ExternalDocs = source.ExternalDocs;
if (source.Example is not null)
target.Example = source.Example;
if (source.Extensions is not null)
target.Extensions = new Dictionary<string, IOpenApiExtension>(source.Extensions);
if (source.Discriminator is not null)
target.Discriminator = source.Discriminator;
if (!string.IsNullOrEmpty(source.Description))
target.Description = source.Description;
if (!string.IsNullOrEmpty(source.Title))
target.Title = source.Title;
if (source.Default is not null)
target.Default = source.Default;
if (source.Reference is not null)
target.Reference = source.Reference;
}
}

private static void PrepareDescriptionForCopilot(OpenApiDocument document)
{
var selectFirstAnyOneOfVisitor = new SelectFirstAnyOneOfVisitor();
var selectFirstAnyOneOfWalker = new OpenApiWalker(selectFirstAnyOneOfVisitor);
selectFirstAnyOneOfWalker.Walk(document);

var allOfPropertiesRetrievalVisitor = new AllOfPropertiesRetrievalVisitor();
var allOfPropertiesRetrievalWalker = new OpenApiWalker(allOfPropertiesRetrievalVisitor);
allOfPropertiesRetrievalWalker.Walk(document);
Expand All @@ -155,41 +245,6 @@ private static void PrepareDescriptionForCopilot(OpenApiDocument document)
mappingCleanupWalker.Walk(document);
}

private static OpenApiDocument InlineRequestBodyAllOf(OpenApiDocument openApiDocument)
{
if (openApiDocument.Paths is null) return openApiDocument;
var contentItems = openApiDocument.Paths.Values.Where(static x => x?.Operations is not null)
.SelectMany(static x => x.Operations.Values.Where(static x => x?.RequestBody?.Content is not null)
.SelectMany(static x => x.RequestBody.Content.Values));
foreach (var contentItem in contentItems)
{
var schema = contentItem.Schema;
schema = SelectFirstAnyOfOrOneOf(schema);
contentItem.Schema = schema;
}

return openApiDocument;

static OpenApiSchema? SelectFirstAnyOfOrOneOf(OpenApiSchema? schema)
{
if (schema?.AnyOf is not { Count: > 0 } && schema?.OneOf is not { Count: > 0 }) return schema;
OpenApiSchema newSchema;
if (schema.AnyOf is { Count: > 0 })
{
newSchema = schema.AnyOf[0];
}
else if (schema.OneOf is { Count: > 0 })
{
newSchema = schema.OneOf[0];
}
else
{
newSchema = schema;
}
return newSchema;
}
}

[GeneratedRegex(@"[^a-zA-Z0-9_]+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)]
private static partial Regex PluginNameCleanupRegex();

Expand Down

0 comments on commit 72d00e5

Please sign in to comment.