Skip to content
Merged
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
5 changes: 4 additions & 1 deletion src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Microsoft.OpenApi.Any;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Readers.ParseNodes;
using Microsoft.OpenApi.Validations;
Expand Down
25 changes: 23 additions & 2 deletions src/Microsoft.OpenApi.Workbench/MainModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Validations;
using Microsoft.OpenApi.Writers;

namespace Microsoft.OpenApi.Workbench
{
Expand All @@ -31,6 +33,11 @@ public class MainModel : INotifyPropertyChanged

private string _renderTime;

/// <summary>
/// Default format.
/// </summary>
private bool _Inline = false;

/// <summary>
/// Default format.
/// </summary>
Expand Down Expand Up @@ -112,6 +119,16 @@ public OpenApiFormat Format
}
}

public bool Inline
{
get => _Inline;
set
{
_Inline = value;
OnPropertyChanged(nameof(Inline));
}
}

public OpenApiSpecVersion Version
{
get => _version;
Expand Down Expand Up @@ -232,11 +249,15 @@ internal void ParseDocument()
private string WriteContents(OpenApiDocument document)
{
var outputStream = new MemoryStream();

document.Serialize(
outputStream,
Version,
Format);

Format,
new OpenApiWriterSettings() {
ReferenceInline = this.Inline == true ? ReferenceInlineSetting.InlineLocalReferences : ReferenceInlineSetting.DoNotInlineReferences
});

outputStream.Position = 0;

return new StreamReader(outputStream).ReadToEnd();
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.OpenApi.Workbench/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<RadioButton GroupName="Format" Content="V3.0.1" Padding="5" Height="24" VerticalAlignment="Top" IsChecked="{Binding IsV3_0}" />
<RadioButton GroupName="Format" Content="V2.0" Padding="5" Height="24" VerticalAlignment="Top" IsChecked="{Binding IsV2_0}" />
</StackPanel>
<CheckBox Name="Inline" Content="Inline" IsChecked="{Binding Inline}" />
</StackPanel>
</StackPanel>
<TextBox x:Name="txtErrors" Margin="10,10,10,10" TextWrapping="Wrap" Text="{Binding Errors}" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" DockPanel.Dock="Top" MaxHeight="100" ScrollViewer.VerticalScrollBarVisibility="Auto" IsReadOnlyCaretVisible="True" IsManipulationEnabled="True" />
Expand Down
26 changes: 26 additions & 0 deletions src/Microsoft.OpenApi/Extensions/OpenAPIWriterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.OpenApi.Writers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.OpenApi
{
internal static class OpenAPIWriterExtensions
{
/// <summary>
/// Temporary extension method until we add Settings property to IOpenApiWriter in next major version
/// </summary>
/// <param name="openApiWriter"></param>
/// <returns></returns>
internal static OpenApiWriterSettings GetSettings(this IOpenApiWriter openApiWriter)
{
if (openApiWriter is OpenApiWriterBase)
{
return ((OpenApiWriterBase)openApiWriter).Settings;
}
return new OpenApiWriterSettings();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public static void Serialize<T>(
this T element,
Stream stream,
OpenApiSpecVersion specVersion,
OpenApiFormat format)
OpenApiFormat format,
OpenApiWriterSettings settings = null)
where T : IOpenApiSerializable
{
if (stream == null)
Expand All @@ -67,10 +68,10 @@ public static void Serialize<T>(
switch (format)
{
case OpenApiFormat.Json:
writer = new OpenApiJsonWriter(streamWriter);
writer = new OpenApiJsonWriter(streamWriter,settings);
break;
case OpenApiFormat.Yaml:
writer = new OpenApiYamlWriter(streamWriter);
writer = new OpenApiYamlWriter(streamWriter, settings);
break;
default:
throw new OpenApiException(string.Format(SRResource.OpenApiFormatNotSupported, format));
Expand All @@ -86,6 +87,7 @@ public static void Serialize<T>(
/// <param name="element">The Open API element.</param>
/// <param name="writer">The output writer.</param>
/// <param name="specVersion">Version of the specification the output should conform to</param>

public static void Serialize<T>(this T element, IOpenApiWriter writer, OpenApiSpecVersion specVersion)
where T : IOpenApiSerializable
{
Expand Down Expand Up @@ -116,6 +118,7 @@ public static void Serialize<T>(this T element, IOpenApiWriter writer, OpenApiSp
writer.Flush();
}


/// <summary>
/// Serializes the <see cref="IOpenApiSerializable"/> to the Open API document as a string in JSON format.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Models/OpenApiCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down
24 changes: 24 additions & 0 deletions src/Microsoft.OpenApi/Models/OpenApiComponents.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
Expand Down Expand Up @@ -76,6 +78,28 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

// If references have been inlined we don't need the to render the components section
// however if they have cycles, then we will need a component rendered
if (writer.GetSettings().ReferenceInline != ReferenceInlineSetting.DoNotInlineReferences)
{
var loops = writer.GetSettings().LoopDetector.Loops;
writer.WriteStartObject();
if (loops.TryGetValue(typeof(OpenApiSchema), out List<object> schemas))
{
var openApiSchemas = schemas.Cast<OpenApiSchema>().Distinct().ToList()
.ToDictionary<OpenApiSchema, string>(k => k.Reference.Id);

writer.WriteOptionalMap(
OpenApiConstants.Schemas,
Schemas,
(w, key, component) => {
component.SerializeAsV3WithoutReference(w);
});
}
writer.WriteEndObject();
return;
}

writer.WriteStartObject();

// Serialize each referenceable object as full object without reference if the reference in the object points to itself.
Expand Down
61 changes: 42 additions & 19 deletions src/Microsoft.OpenApi/Models/OpenApiDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,27 +126,50 @@ public void SerializeAsV2(IOpenApiWriter writer)
// paths
writer.WriteRequiredObject(OpenApiConstants.Paths, Paths, (w, p) => p.SerializeAsV2(w));

// Serialize each referenceable object as full object without reference if the reference in the object points to itself.
// If the reference exists but points to other objects, the object is serialized to just that reference.

// definitions
writer.WriteOptionalMap(
OpenApiConstants.Definitions,
Components?.Schemas,
(w, key, component) =>
// If references have been inlined we don't need the to render the components section
// however if they have cycles, then we will need a component rendered
if (writer.GetSettings().ReferenceInline != ReferenceInlineSetting.DoNotInlineReferences)
{
var loops = writer.GetSettings().LoopDetector.Loops;
writer.WriteStartObject();
if (loops.TryGetValue(typeof(OpenApiSchema), out List<object> schemas))
{
if (component.Reference != null &&
component.Reference.Type == ReferenceType.Schema &&
component.Reference.Id == key)
{
component.SerializeAsV2WithoutReference(w);
}
else
var openApiSchemas = schemas.Cast<OpenApiSchema>().Distinct().ToList()
.ToDictionary<OpenApiSchema, string>(k => k.Reference.Id);

writer.WriteOptionalMap(
OpenApiConstants.Definitions,
openApiSchemas,
(w, key, component) =>
{
component.SerializeAsV2WithoutReference(w);
});
}
writer.WriteEndObject();
return;
}
else
{
// Serialize each referenceable object as full object without reference if the reference in the object points to itself.
// If the reference exists but points to other objects, the object is serialized to just that reference.
// definitions
writer.WriteOptionalMap(
OpenApiConstants.Definitions,
Components?.Schemas,
(w, key, component) =>
{
component.SerializeAsV2(w);
}
});

if (component.Reference != null &&
component.Reference.Type == ReferenceType.Schema &&
component.Reference.Id == key)
{
component.SerializeAsV2WithoutReference(w);
}
else
{
component.SerializeAsV2(w);
}
});
}
// parameters
writer.WriteOptionalMap(
OpenApiConstants.Parameters,
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Models/OpenApiExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Models/OpenApiHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down Expand Up @@ -161,7 +161,7 @@ public void SerializeAsV2(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV2(writer);
return;
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Models/OpenApiLink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Models/OpenApiParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down Expand Up @@ -210,7 +210,7 @@ public void SerializeAsV2(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV2(writer);
return;
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Models/OpenApiResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
Expand Down Expand Up @@ -105,7 +105,7 @@ public void SerializeAsV2(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)
if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV2(writer);
return;
Expand Down
25 changes: 22 additions & 3 deletions src/Microsoft.OpenApi/Models/OpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,31 @@ public void SerializeAsV3(IOpenApiWriter writer)
throw Error.ArgumentNull(nameof(writer));
}

var settings = writer.GetSettings();

if (Reference != null)
{
Reference.SerializeAsV3(writer);
return;
if (settings.ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV3(writer);
return;
}

// If Loop is detected then just Serialize as a reference.
if (!settings.LoopDetector.PushLoop<OpenApiSchema>(this))
{
settings.LoopDetector.SaveLoop(this);
Reference.SerializeAsV3(writer);
return;
}
}

SerializeAsV3WithoutReference(writer);

if (Reference != null)
{
settings.LoopDetector.PopLoop<OpenApiSchema>();
}
}

/// <summary>
Expand Down Expand Up @@ -424,7 +442,8 @@ internal void SerializeAsV2(
throw Error.ArgumentNull(nameof(writer));
}

if (Reference != null)

if (Reference != null && writer.GetSettings().ReferenceInline != ReferenceInlineSetting.InlineLocalReferences)
{
Reference.SerializeAsV2(writer);
return;
Expand Down
Loading