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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Preserve properties and referenced models inside a single inline `allOf` object.
- Dart: escape enum options named value or values to avoid conflicts with generated and built-in enum members. [#7807](https://github.com/microsoft/kiota/issues/7807)
- C#: escape Unicode line and paragraph separators in generated string literals so generated clients remain valid C# source.
- External reference allowlist wildcards no longer cross the URI authority boundary, so a wildcard in the scheme or host cannot match text in the path, the user information or the port.
Expand Down
7 changes: 7 additions & 0 deletions src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,13 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, IOp
return CreateModelDeclarationAndType(currentNode, mergedSchema, operation, codeNamespace, suffix, response: responseValue, typeNameForInlineSchema: typeNameForInlineSchema, isRequestBody, dynamicBindingSuffixContext: suffixForInlineSchema);
}

if (schema.AllOf is { Count: 1 } && !schema.AllOf[0].IsReferencedSchema() && schema.AllOf[0].HasAnyProperty() &&
schema.MergeAllOfSchemaEntries() is IOpenApiSchema singleInlineSchema)
{
// A single inline object still contributes properties, even without an inheritance relationship.
return CreateModelDeclarationAndType(currentNode, singleInlineSchema, operation, codeNamespace, suffix, response: responseValue, typeNameForInlineSchema: typeNameForInlineSchema, isRequestBody, dynamicBindingSuffixContext: suffixForInlineSchema);
}

if ((schema.IsInclusiveUnion() || schema.IsExclusiveUnion()) && string.IsNullOrEmpty(schema.Format)
&& !schema.IsODataPrimitiveType())
{ // OData types are oneOf string, type + format, enum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Threading.Tasks;

using Kiota.Builder.CodeDOM;
using Kiota.Builder.Configuration;

using Microsoft.Extensions.Logging.Abstractions;

using Xunit;

namespace Kiota.Builder.Tests;

public sealed partial class KiotaBuilderTests
{
[Theory]
[InlineData(true, true)]
[InlineData(true, false)]
[InlineData(false, true)]
[InlineData(true, true, true)]
public async Task SingleInlineAllOfPreservesReferencedPropertiesAsync(bool wrapped, bool explicitType, bool siblingProperty = false)
{
const string inlineSchema = """
{"type":"object","required":["other"],"properties":{
"other":{"$ref":"#/components/schemas/Identification"}
}}
""";
var accountSchema = wrapped ? "{" + (explicitType ? "\"type\":\"object\"," : "") +
(siblingProperty ? "\"properties\":{\"label\":{\"type\":\"string\"}}," : "") +
"\"allOf\":[" + inlineSchema + "]}" : inlineSchema;
var description = """
{
"openapi":"3.0.3","info":{"title":"Single inline allOf","version":"1.0"},
"paths":{"/account":{"get":{"responses":{"200":{"description":"Success","content":{
"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}
}}}}}},
"components":{"schemas":{
"Account":ACCOUNT_SCHEMA,
"Identification":{"type":"object","properties":{"identification":{"type":"string"}}}
}}
}
""".Replace("ACCOUNT_SCHEMA", accountSchema);
await using var stream = await GetDocumentStreamAsync(description);
var builder = new KiotaBuilder(NullLogger<KiotaBuilder>.Instance,
new GenerationConfiguration { IncludeAdditionalData = false }, _httpClient);
var document = await builder.CreateOpenApiDocumentAsync(stream, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(document);
var model = builder.CreateSourceModel(builder.CreateUriSpace(document));
var account = model.FindChildByName<CodeClass>("Account");
Assert.NotNull(account);
var other = Assert.Single(account.Properties, static p => p.Name == "other");
Assert.Equal("other", other.Name);
if (siblingProperty)
Assert.Contains(account.Properties, static p => p.Name == "label");
var identification = model.FindChildByName<CodeClass>("Identification");
Assert.NotNull(identification);
Assert.Same(identification, Assert.IsType<CodeType>(other.Type).TypeDefinition);
Assert.Contains(identification.Properties, static p => p.Name == "identification");
}
}
Loading