Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/feature/improve-yaml' into yam…
Browse files Browse the repository at this point in the history
…l_references

# Conflicts:
#	src/NSwag.Commands/NSwag.Commands.csproj
#	src/NSwag.Core.Yaml/SwaggerYamlDocument.cs
#	src/NSwag.Core/SwaggerDocument.cs
  • Loading branch information
Em1ss1oN committed Jul 21, 2018
2 parents 4e87cfa + bcbb6ef commit 0c9818b
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/NSwag.Commands/Commands/IsolatedCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private static string[] GetAllReferencePaths(string[] assemblyPaths, string[] re
#if NET451
public IEnumerable<string> GetAssemblies(string assemblyDirectory)
{
var codeBaseDirectory = Path.GetDirectoryName(typeof(IsolatedSwaggerOutputCommandBase).GetTypeInfo()
var codeBaseDirectory = Path.GetDirectoryName(typeof(IsolatedCommandBase<>).GetTypeInfo()
.Assembly.CodeBase.Replace("file:///", string.Empty));

yield return codeBaseDirectory + "/Newtonsoft.Json.dll";
Expand Down
13 changes: 11 additions & 2 deletions src/NSwag.Commands/Commands/IsolatedSwaggerOutputCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@
using NConsole;
using Newtonsoft.Json;
using NJsonSchema;
using NJsonSchema.Generation;
using NJsonSchema.Infrastructure;
using NJsonSchema.Yaml;
using NSwag.AssemblyLoader.Utilities;

namespace NSwag.Commands
{
/// <summary>A command which is run in isolation.</summary>
public abstract class IsolatedSwaggerOutputCommandBase : IsolatedCommandBase<string>, IOutputCommand
public abstract class IsolatedSwaggerOutputCommandBase<T> : IsolatedCommandBase<string>, IOutputCommand
where T : JsonSchemaGeneratorSettings
{
/// <summary>Initializes a new instance of the <see cref="IsolatedSwaggerOutputCommandBase"/> class.</summary>
protected IsolatedSwaggerOutputCommandBase()
{
OutputType = SchemaType.Swagger2;
}

[JsonIgnore]
public abstract T Settings { get; }

[Argument(Name = "Output", IsRequired = false, Description = "The output file path (optional).")]
[JsonProperty("output", NullValueHandling = NullValueHandling.Include)]
public string OutputFilePath { get; set; }
Expand All @@ -37,8 +43,11 @@ protected IsolatedSwaggerOutputCommandBase()

public override async Task<object> RunAsync(CommandLineProcessor processor, IConsoleHost host)
{
JsonReferenceResolver ReferenceResolverFactory(SwaggerDocument d) =>
new JsonAndYamlReferenceResolver(new JsonSchemaResolver(d, Settings));

var documentJson = await RunIsolatedAsync((string)null);
var document = await SwaggerDocument.FromJsonAsync(documentJson, expectedSchemaType: OutputType).ConfigureAwait(false);
var document = await SwaggerDocument.FromJsonAsync(documentJson, null, OutputType, ReferenceResolverFactory).ConfigureAwait(false);
await this.TryWriteDocumentOutputAsync(host, () => document).ConfigureAwait(false);
return document;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
using NConsole;
using Newtonsoft.Json;
using NSwag.SwaggerGeneration.AspNetCore;
using NJsonSchema.Yaml;
using Newtonsoft.Json.Schema;
using NJsonSchema;

#if NETSTANDARD
using System.Runtime.Loader;
Expand Down Expand Up @@ -167,8 +170,11 @@ public override async Task<object> RunAsync(CommandLineProcessor processor, ICon

host?.WriteMessage($"Output written to {outputFile}.{Environment.NewLine}");

JsonReferenceResolver ReferenceResolverFactory(SwaggerDocument d) =>
new JsonAndYamlReferenceResolver(new NJsonSchema.JsonSchemaResolver(d, Settings));

var documentJson = File.ReadAllText(outputFile);
var document = await SwaggerDocument.FromJsonAsync(documentJson, expectedSchemaType: OutputType).ConfigureAwait(false);
var document = await SwaggerDocument.FromJsonAsync(documentJson, null, OutputType, ReferenceResolverFactory).ConfigureAwait(false);
await this.TryWriteDocumentOutputAsync(host, () => document).ConfigureAwait(false);
return document;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
namespace NSwag.Commands.SwaggerGeneration
{
/// <inheritdoc />
public abstract class SwaggerGeneratorCommandBase<T> : IsolatedSwaggerOutputCommandBase
public abstract class SwaggerGeneratorCommandBase<T> : IsolatedSwaggerOutputCommandBase<T>
where T : SwaggerGeneratorSettings, new()
{
/// <summary>Initializes a new instance of the <see cref="SwaggerGeneratorCommandBase{T}"/> class.</summary>
Expand All @@ -31,7 +31,7 @@ protected SwaggerGeneratorCommandBase()
}

[JsonIgnore]
public T Settings { get; }
public override T Settings { get; }

[Argument(Name = nameof(DefaultPropertyNameHandling), IsRequired = false, Description = "The default property name handling ('Default' or 'CamelCase').")]
public PropertyNameHandling DefaultPropertyNameHandling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace NSwag.Commands.SwaggerGeneration
{
/// <summary></summary>
[Command(Name = "types2swagger")]
public class TypesToSwaggerCommand : IsolatedSwaggerOutputCommandBase
public class TypesToSwaggerCommand : IsolatedSwaggerOutputCommandBase<JsonSchemaGeneratorSettings>
{
/// <summary>Initializes a new instance of the <see cref="TypesToSwaggerCommand"/> class.</summary>
public TypesToSwaggerCommand()
Expand All @@ -30,7 +30,7 @@ public TypesToSwaggerCommand()
}

[JsonIgnore]
public new JsonSchemaGeneratorSettings Settings { get; }
public override JsonSchemaGeneratorSettings Settings { get; }

[Argument(Name = "ClassNames", Description = "The class names.")]
public string[] ClassNames { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/NSwag.Commands/NSwag.Commands.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="NConsole" Version="3.9.6519.30868" />
<PackageReference Include="NJsonSchema" Version="9.10.64" />
<PackageReference Include="NJsonSchema.Yaml" Version="9.10.64" />
<PackageReference Include="NJsonSchema.CodeGeneration" Version="9.10.64" />
<PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="9.10.64" />
<PackageReference Include="NJsonSchema.CodeGeneration.TypeScript" Version="9.10.64" />
Expand Down
36 changes: 32 additions & 4 deletions src/NSwag.Core.Yaml/SwaggerYamlDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,48 @@ namespace NSwag
public static class SwaggerYamlDocument
{
/// <summary>Creates a Swagger specification from a YAML string.</summary>
/// <param name="data">The JSON data.</param>
/// <param name="data">The JSON or YAML data.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static Task<SwaggerDocument> FromYamlAsync(string data)
{
return FromYamlAsync(data, null, SchemaType.Swagger2, null);
}

/// <summary>Creates a Swagger specification from a YAML string.</summary>
/// <param name="data">The JSON or YAML data.</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static Task<SwaggerDocument> FromYamlAsync(string data, string documentPath)
{
return FromYamlAsync(data, documentPath, SchemaType.Swagger2, null);
}

/// <summary>Creates a Swagger specification from a YAML string.</summary>
/// <param name="data">The JSON or YAML data.</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <param name="expectedSchemaType">The expected schema type which is used when the type cannot be determined.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static async Task<SwaggerDocument> FromYamlAsync(string data, string documentPath = null)
public static Task<SwaggerDocument> FromYamlAsync(string data, string documentPath, SchemaType expectedSchemaType)
{
return FromYamlAsync(data, documentPath, expectedSchemaType, null);
}

/// <summary>Creates a Swagger specification from a YAML string.</summary>
/// <param name="data">The JSON or YAML data.</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <param name="expectedSchemaType">The expected schema type which is used when the type cannot be determined.</param>
/// <param name="referenceResolverFactory">The JSON reference resolver factory.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static async Task<SwaggerDocument> FromYamlAsync(string data, string documentPath = null, SchemaType expectedSchemaType = SchemaType.Swagger2, Func<SwaggerDocument, JsonReferenceResolver> referenceResolverFactory = null)
{
var deserializer = new DeserializerBuilder().Build();
var yamlObject = deserializer.Deserialize(new StringReader(data));

var serializer = new SerializerBuilder()
.JsonCompatible()
.Build();

var json = serializer.Serialize(yamlObject);
return await SwaggerDocument.FromJsonAsync(json, CreateReferenceResolverFactory(), documentPath).ConfigureAwait(false);
return await SwaggerDocument.FromJsonAsync(json, documentPath, expectedSchemaType, referenceResolverFactory).ConfigureAwait(false);
}

/// <summary>Converts the Swagger specification to YAML.</summary>
Expand Down
52 changes: 33 additions & 19 deletions src/NSwag.Core/SwaggerDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,40 @@ public string ToJson(SchemaType schemaType, Formatting formatting)
return JsonSchemaSerialization.ToJson(this, schemaType, contractResolver, formatting);
}

/// <summary>Creates a Swagger specification from a JSON string.</summary>
/// <param name="data">The JSON data.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static Task<SwaggerDocument> FromJsonAsync(string data)
{
return FromJsonAsync(data, null, SchemaType.Swagger2, null);
}

/// <summary>Creates a Swagger specification from a JSON string.</summary>
/// <param name="data">The JSON data.</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static Task<SwaggerDocument> FromJsonAsync(string data, string documentPath)
{
return FromJsonAsync(data, documentPath, SchemaType.Swagger2, null);
}

/// <summary>Creates a Swagger specification from a JSON string.</summary>
/// <param name="data">The JSON data.</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <param name="expectedSchemaType">The expected schema type which is used when the type cannot be determined.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
public static async Task<SwaggerDocument> FromJsonAsync(string data, string documentPath = null, SchemaType expectedSchemaType = SchemaType.Swagger2)
public static Task<SwaggerDocument> FromJsonAsync(string data, string documentPath, SchemaType expectedSchemaType)
{
return await FromJsonAsync(data, CreateDefaultReferenceResolverFactory(), documentPath, expectedSchemaType).ConfigureAwait(false);
return FromJsonAsync(data, documentPath, expectedSchemaType, null);
}

/// <summary>Creates a Swagger specification from a JSON string.</summary>
/// <param name="data">The JSON data.</param>
/// <param name="referenceResolverFactory">The JSON Schema reference resolver factory for custom resolution of relative document references</param>
/// <param name="documentPath">The document path (URL or file path) for resolving relative document references.</param>
/// <param name="expectedSchemaType">The expected schema type which is used when the type cannot be determined.</param>
/// <param name="referenceResolverFactory">The JSON reference resolver factory.</param>
/// <returns>The <see cref="SwaggerDocument"/>.</returns>
/// <exception cref="NotSupportedException">If expectedSchemaType is not supported.</exception>
public static async Task<SwaggerDocument> FromJsonAsync(string data, Func<SwaggerDocument, JsonReferenceResolver> referenceResolverFactory, string documentPath = null, SchemaType expectedSchemaType = SchemaType.Swagger2)
public static async Task<SwaggerDocument> FromJsonAsync(string data, string documentPath, SchemaType expectedSchemaType, Func<SwaggerDocument, JsonReferenceResolver> referenceResolverFactory)
{
// For explanation of the regex use https://regexr.com/ and the below unescaped pattern that is without named groups
// (?:\"(openapi|swagger)\")(?:\s*:\s*)(?:\"([^"]*)\")
Expand All @@ -172,14 +188,21 @@ public static async Task<SwaggerDocument> FromJsonAsync(string data, Func<Swagge
{
throw new NotSupportedException("The schema type JsonSchema is not supported.");
}

var contractResolver = CreateJsonSerializerContractResolver(expectedSchemaType);
Func<SwaggerDocument, JsonReferenceResolver> factory = document =>
return await JsonSchemaSerialization.FromJsonAsync<SwaggerDocument>(data, expectedSchemaType, documentPath, document =>
{
document.SchemaType = expectedSchemaType;
return referenceResolverFactory(document);
};
return await JsonSchemaSerialization.FromJsonAsync(data, expectedSchemaType, documentPath, factory, contractResolver).ConfigureAwait(false);
if (referenceResolverFactory != null)
{
return referenceResolverFactory(document);
}
else
{
var schemaResolver = new SwaggerSchemaResolver(document, new JsonSchemaGeneratorSettings());
return new JsonReferenceResolver(schemaResolver);
}
}, contractResolver).ConfigureAwait(false);
}

/// <summary>Creates a Swagger specification from a JSON file.</summary>
Expand Down Expand Up @@ -263,14 +286,5 @@ private string GetOperationNameFromPath(SwaggerOperationDescription operation)
var lastPathSegment = pathSegments.LastOrDefault(s => !s.Contains("{"));
return string.IsNullOrEmpty(lastPathSegment) ? "Anonymous" : lastPathSegment;
}

private static Func<SwaggerDocument, JsonReferenceResolver> CreateDefaultReferenceResolverFactory()
{
return document =>
{
var schemaResolver = new SwaggerSchemaResolver(document, new JsonSchemaGeneratorSettings());
return new JsonReferenceResolver(schemaResolver);
};
}
}
}
4 changes: 4 additions & 0 deletions src/NSwag.Tests/NSwag.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@
<Project>{2E6174AA-FC75-4821-9E86-51B30568BEC0}</Project>
<Name>NSwag.Core</Name>
</ProjectReference>
<ProjectReference Include="..\NSwag.SwaggerGeneration.WebApi\NSwag.SwaggerGeneration.WebApi.csproj">
<Project>{8A547CB0-930F-466D-92EB-E780FF14C0A6}</Project>
<Name>NSwag.SwaggerGeneration.WebApi</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config">
Expand Down
4 changes: 4 additions & 0 deletions src/NSwagStudio/NSwagStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@
<Project>{2E6174AA-FC75-4821-9E86-51B30568BEC0}</Project>
<Name>NSwag.Core</Name>
</ProjectReference>
<ProjectReference Include="..\NSwag.SwaggerGeneration.AspNetCore\NSwag.SwaggerGeneration.AspNetCore.csproj">
<Project>{51740C29-AF4F-40AD-BFDE-09E6F8C873D2}</Project>
<Name>NSwag.SwaggerGeneration.AspNetCore</Name>
</ProjectReference>
<ProjectReference Include="..\NSwag.SwaggerGeneration.WebApi\NSwag.SwaggerGeneration.WebApi.csproj">
<Project>{8A547CB0-930F-466D-92EB-E780FF14C0A6}</Project>
<Name>NSwag.SwaggerGeneration.WebApi</Name>
Expand Down

0 comments on commit 0c9818b

Please sign in to comment.