Add model reference support to library and command line utility. (#81)
* Support many conversion options in the command-line tool. Support local reference files in file-based csdl in the library and command-line tool. * Added tests for references. * Updates from github review.
This commit is contained in:
parent
f6f26df6f2
commit
c1aa5a6f94
|
@ -162,7 +162,7 @@ namespace Microsoft.OpenApi.OData.Edm
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the operaiton is overload in the model.
|
||||
/// Check whether the operation is overload in the model.
|
||||
/// </summary>
|
||||
/// <param name="model">The Edm model.</param>
|
||||
/// <param name="operation">The test operations.</param>
|
||||
|
@ -172,7 +172,7 @@ namespace Microsoft.OpenApi.OData.Edm
|
|||
Utils.CheckArgumentNull(model, nameof(model));
|
||||
Utils.CheckArgumentNull(operation, nameof(operation));
|
||||
|
||||
return model.SchemaElements.OfType<IEdmOperation>()
|
||||
return model.GetAllElements().OfType<IEdmOperation>()
|
||||
.Where(o => o.IsBound == operation.IsBound && o.FullName() == operation.FullName() &&
|
||||
o.Parameters.First().Type.Definition == operation.Parameters.First().Type.Definition
|
||||
).Count() > 1;
|
||||
|
@ -197,5 +197,28 @@ namespace Microsoft.OpenApi.OData.Edm
|
|||
return model.EntityContainer.OperationImports()
|
||||
.Where(o => o.Operation.IsBound == operationImport.Operation.IsBound && o.Name == operationImport.Name).Count() > 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all of the elements in the model and its referenced models.
|
||||
/// </summary>
|
||||
/// <returns>All the elements.</returns>
|
||||
public static IEnumerable<IEdmSchemaElement> GetAllElements(this IEdmModel model)
|
||||
{
|
||||
foreach (var element in model.SchemaElements.Where(el =>
|
||||
!ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
|
||||
{
|
||||
yield return element;
|
||||
}
|
||||
|
||||
foreach (var refModel in model.ReferencedModels)
|
||||
{
|
||||
foreach (var element in refModel.SchemaElements.Where(el =>
|
||||
!ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
|
||||
{
|
||||
yield return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace Microsoft.OpenApi.OData.Edm
|
|||
{
|
||||
IDictionary<string, IList<IEdmOperation>> edmOperationDict = new Dictionary<string, IList<IEdmOperation>>();
|
||||
|
||||
foreach (var edmOperation in Model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
|
||||
foreach (var edmOperation in Model.GetAllElements().OfType<IEdmOperation>().Where(e => e.IsBound))
|
||||
{
|
||||
IEdmOperationParameter bindingParameter = edmOperation.Parameters.First();
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ namespace Microsoft.OpenApi.OData.Edm
|
|||
/// </summary>
|
||||
private void RetrieveBoundOperationPaths()
|
||||
{
|
||||
foreach (var edmOperation in _model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
|
||||
foreach (var edmOperation in _model.GetAllElements().OfType<IEdmOperation>().Where(e => e.IsBound))
|
||||
{
|
||||
if (!CanFilter(edmOperation))
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// ------------------------------------------------------------
|
||||
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.OData.Edm;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Generator
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (var element in model.SchemaElements)
|
||||
foreach (var element in model.GetAllElements())
|
||||
{
|
||||
switch (element.SchemaElementKind)
|
||||
{
|
||||
|
|
|
@ -34,7 +34,11 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
|
||||
// Each entity type, complex type, enumeration type, and type definition directly
|
||||
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
|
||||
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
|
||||
// Ideally this would be driven off the types used in the paths, but in practice, it is simply
|
||||
// all of the types present in the model.
|
||||
IEnumerable<IEdmSchemaElement> elements = context.Model.GetAllElements();
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
switch (element.SchemaElementKind)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,11 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
|
||||
// Each entity type, complex type, enumeration type, and type definition directly
|
||||
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
|
||||
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
|
||||
// Ideally this would be driven off the types used in the paths, but in practice, it is simply
|
||||
// all of the types present in the model.
|
||||
IEnumerable<IEdmSchemaElement> elements = context.Model.GetAllElements();
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
switch (element.SchemaElementKind)
|
||||
{
|
||||
|
|
27
src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs
Normal file
27
src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.OpenApi.OData
|
||||
{
|
||||
internal static class ODataConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Namespaces used in standard included models.
|
||||
/// </summary>
|
||||
public static IList<string> StandardNamespaces = new List<string>
|
||||
{
|
||||
"Org.OData.",
|
||||
"Edm",
|
||||
"OData.Community.",
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -45,6 +45,11 @@ namespace OoasUtil
|
|||
/// </summary>
|
||||
public OpenApiFormat? Format { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether KeyAsSegment is used.
|
||||
/// </summary>
|
||||
public bool? KeyAsSegment { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output OpenApi Specification Version.
|
||||
/// </summary>
|
||||
|
@ -60,6 +65,31 @@ namespace OoasUtil
|
|||
/// </summary>
|
||||
public bool IsLocalFile { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the output to produce all derived types in responses.
|
||||
/// </summary>
|
||||
public bool? DerivedTypesReferencesForResponses { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the output to expect all derived types in request bodies.
|
||||
/// </summary>
|
||||
public bool? DerivedTypesReferencesForRequestBody { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the output to expose pagination for collections.
|
||||
/// </summary>
|
||||
public bool? EnablePagination { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// tSet the output to use unqualified calls for bound operations.
|
||||
/// </summary>
|
||||
public bool? EnableUnqualifiedCall { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// tDisable examples in the schema.
|
||||
/// </summary>
|
||||
public bool? DisableSchemaExamples { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Process the arguments.
|
||||
/// </summary>
|
||||
|
@ -98,6 +128,14 @@ namespace OoasUtil
|
|||
i++;
|
||||
break;
|
||||
|
||||
case "--keyassegment":
|
||||
case "-k":
|
||||
if (!ProcessKeyAsSegment(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "--yaml":
|
||||
case "-y":
|
||||
if (!ProcessTarget(OpenApiFormat.Yaml))
|
||||
|
@ -132,6 +170,46 @@ namespace OoasUtil
|
|||
i++;
|
||||
break;
|
||||
|
||||
case "--derivedtypesreferencesforresponses":
|
||||
case "-drs":
|
||||
if (!ProcessDerivedTypesReferencesForResponses(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "--derivedtypesreferencesforrequestbody":
|
||||
case "-drq":
|
||||
if (!ProcessDerivedTypesReferencesForRequestBody(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "--enablepagination":
|
||||
case "-p":
|
||||
if (!ProcessEnablePagination(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "--enableunqualifiedcall":
|
||||
case "-u":
|
||||
if (!ProcessEnableUnqualifiedCall(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "--disableschemaexamples":
|
||||
case "-x":
|
||||
if (!ProcessDisableSchemaExamples(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PrintUsage();
|
||||
return false;
|
||||
|
@ -155,6 +233,36 @@ namespace OoasUtil
|
|||
Version = OpenApiSpecVersion.OpenApi3_0;
|
||||
}
|
||||
|
||||
if (KeyAsSegment == null)
|
||||
{
|
||||
KeyAsSegment = false;
|
||||
}
|
||||
|
||||
if (DerivedTypesReferencesForResponses == null)
|
||||
{
|
||||
DerivedTypesReferencesForResponses = false;
|
||||
}
|
||||
|
||||
if (DerivedTypesReferencesForRequestBody == null)
|
||||
{
|
||||
DerivedTypesReferencesForRequestBody = false;
|
||||
}
|
||||
|
||||
if (EnablePagination == null)
|
||||
{
|
||||
EnablePagination = false;
|
||||
}
|
||||
|
||||
if (EnableUnqualifiedCall == null)
|
||||
{
|
||||
EnableUnqualifiedCall = false;
|
||||
}
|
||||
|
||||
if (DisableSchemaExamples == null)
|
||||
{
|
||||
DisableSchemaExamples = false;
|
||||
}
|
||||
|
||||
_continue = ValidateArguments();
|
||||
return _continue;
|
||||
}
|
||||
|
@ -198,6 +306,84 @@ namespace OoasUtil
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessKeyAsSegment(bool keyAsSegment)
|
||||
{
|
||||
if (KeyAsSegment != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--keyassegment|-k] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyAsSegment = keyAsSegment;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessDerivedTypesReferencesForResponses(bool derivedTypesReferencesForResponses)
|
||||
{
|
||||
if (DerivedTypesReferencesForResponses != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforresponses|-drs] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
DerivedTypesReferencesForResponses = derivedTypesReferencesForResponses;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessDerivedTypesReferencesForRequestBody(bool derivedTypesReferencesForRequestBody)
|
||||
{
|
||||
if (DerivedTypesReferencesForRequestBody != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforrequestbody|-drq] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
DerivedTypesReferencesForRequestBody = derivedTypesReferencesForRequestBody;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessEnablePagination(bool enablePagination)
|
||||
{
|
||||
if (EnablePagination != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--enablepagination|-p] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
EnablePagination = enablePagination;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessEnableUnqualifiedCall(bool enableUnqualifiedCall)
|
||||
{
|
||||
if (EnableUnqualifiedCall != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--enableunqualifiedcall|-u] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
EnableUnqualifiedCall = enableUnqualifiedCall;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessDisableSchemaExamples(bool disableSchemaExamples)
|
||||
{
|
||||
if (DisableSchemaExamples != null)
|
||||
{
|
||||
Console.WriteLine("[Error:] Multiple [--disableschemaexamples|-x] are not allowed.\n");
|
||||
PrintUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
DisableSchemaExamples = disableSchemaExamples;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessTarget(int version)
|
||||
{
|
||||
if (Version != null)
|
||||
|
@ -256,6 +442,12 @@ namespace OoasUtil
|
|||
sb.Append(" --version|-v\t\t\tDisplay version.\n");
|
||||
sb.Append(" --input|-i CsdlFileOrUrl\tSet the CSDL file name or the OData Service Url.\n");
|
||||
sb.Append(" --output|-o OutputFile\tSet the output file name.\n");
|
||||
sb.Append(" --keyassegment|-k\t\t\tSet the output to use key-as-segment style URLs.\n");
|
||||
sb.Append(" --derivedtypesreferencesforresponses|-drs\t\t\tSet the output to produce all derived types in responses.\n");
|
||||
sb.Append(" --derivedtypesreferencesforrequestbody|-drq\t\t\tSet the output to expect all derived types in request bodies.\n");
|
||||
sb.Append(" --enablepagination|-p\t\t\tSet the output to expose pagination for collections.\n");
|
||||
sb.Append(" --enableunqualifiedcall|-u\t\t\tSet the output to use unqualified calls for bound operations.\n");
|
||||
sb.Append(" --disableschemaexamples|-x\t\t\tDisable examples in the schema.\n");
|
||||
sb.Append(" --json|-j\t\t\tSet the output format as JSON.\n");
|
||||
sb.Append(" --yaml|-y\t\t\tSet the output format as YAML.\n");
|
||||
sb.Append(" --specversion|-s IntVersion\tSet the OpenApi Specification version of the output. Only 2 or 3 are supported.\n");
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Csdl;
|
||||
using Microsoft.OpenApi;
|
||||
using Microsoft.OpenApi.OData;
|
||||
|
||||
namespace OoasUtil
|
||||
{
|
||||
|
@ -28,9 +31,10 @@ namespace OoasUtil
|
|||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="target">The output target.</param>
|
||||
public FileOpenApiGenerator(string input, string output, OpenApiFormat format, OpenApiSpecVersion version)
|
||||
: base(output, format, version)
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="settings">Conversion settings.</param>
|
||||
public FileOpenApiGenerator(string input, string output, OpenApiFormat format, OpenApiConvertSettings settings)
|
||||
: base(output, format, settings)
|
||||
{
|
||||
Input = input;
|
||||
}
|
||||
|
@ -43,7 +47,32 @@ namespace OoasUtil
|
|||
try
|
||||
{
|
||||
string csdl = File.ReadAllText(Input);
|
||||
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
|
||||
var directory = Path.GetDirectoryName(Input);
|
||||
var parsed = XElement.Parse(csdl);
|
||||
using (XmlReader mainReader = parsed.CreateReader())
|
||||
{
|
||||
return CsdlReader.Parse(mainReader, u =>
|
||||
{
|
||||
// Currently only support relative paths
|
||||
if (u.IsAbsoluteUri)
|
||||
{
|
||||
Console.WriteLine($"Referenced model must use relative paths to the main model.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var file = Path.Combine(directory, u.OriginalString);
|
||||
string referenceText = File.ReadAllText(file);
|
||||
var referenceParsed = XElement.Parse(referenceText);
|
||||
XmlReader referenceReader = referenceParsed.CreateReader();
|
||||
return referenceReader;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (EdmParseException parseException)
|
||||
{
|
||||
Console.WriteLine("Failed to parse the CSDL file.");
|
||||
Console.WriteLine(string.Join(Environment.NewLine, parseException.Errors.Select(e => e.ToString())));
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -24,27 +24,27 @@ namespace OoasUtil
|
|||
/// </summary>
|
||||
public OpenApiFormat Format { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Output specification version.
|
||||
/// </summary>
|
||||
public OpenApiSpecVersion Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Output file.
|
||||
/// </summary>
|
||||
public string Output { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Settings to use for conversion.
|
||||
/// </summary>
|
||||
public OpenApiConvertSettings Settings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OpenApiGenerator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="target">The output target.</param>
|
||||
public OpenApiGenerator(string output, OpenApiFormat format, OpenApiSpecVersion version)
|
||||
/// <param name="format">The output format.</param>
|
||||
/// <param name="settings">Conversion settings.</param>
|
||||
public OpenApiGenerator(string output, OpenApiFormat format, OpenApiConvertSettings settings)
|
||||
{
|
||||
Output = output;
|
||||
Format = format;
|
||||
Version = version;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,14 +56,12 @@ namespace OoasUtil
|
|||
{
|
||||
IEdmModel edmModel = GetEdmModel();
|
||||
|
||||
OpenApiConvertSettings settings = GetSettings();
|
||||
|
||||
settings.OpenApiSpecVersion = Version;
|
||||
this.ModifySettings();
|
||||
|
||||
using (FileStream fs = File.Create(Output))
|
||||
{
|
||||
OpenApiDocument document = edmModel.ConvertToOpenApi(settings);
|
||||
document.Serialize(fs, settings.OpenApiSpecVersion, Format);
|
||||
OpenApiDocument document = edmModel.ConvertToOpenApi(Settings);
|
||||
document.Serialize(fs, Settings.OpenApiSpecVersion, Format);
|
||||
fs.Flush();
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +74,8 @@ namespace OoasUtil
|
|||
return true;
|
||||
}
|
||||
|
||||
protected virtual OpenApiConvertSettings GetSettings()
|
||||
protected virtual void ModifySettings()
|
||||
{
|
||||
return new OpenApiConvertSettings();
|
||||
}
|
||||
|
||||
protected abstract IEdmModel GetEdmModel();
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.OpenApi.OData;
|
||||
|
||||
namespace OoasUtil
|
||||
{
|
||||
|
@ -29,13 +31,25 @@ namespace OoasUtil
|
|||
}
|
||||
|
||||
OpenApiGenerator generator;
|
||||
|
||||
OpenApiConvertSettings settings = new OpenApiConvertSettings
|
||||
{
|
||||
EnableKeyAsSegment = processer.KeyAsSegment,
|
||||
EnableDerivedTypesReferencesForResponses = processer.DerivedTypesReferencesForResponses.Value,
|
||||
EnableDerivedTypesReferencesForRequestBody = processer.DerivedTypesReferencesForRequestBody.Value,
|
||||
EnablePagination = processer.EnablePagination.Value,
|
||||
EnableUnqualifiedCall = processer.EnableUnqualifiedCall.Value,
|
||||
ShowSchemaExamples = !processer.DisableSchemaExamples.Value,
|
||||
OpenApiSpecVersion = processer.Version.Value,
|
||||
};
|
||||
|
||||
if (processer.IsLocalFile)
|
||||
{
|
||||
generator = new FileOpenApiGenerator(processer.Input, processer.Output, processer.Format.Value, processer.Version.Value);
|
||||
generator = new FileOpenApiGenerator(processer.Input, processer.Output, processer.Format.Value, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator = new UrlOpenApiGenerator(new Uri(processer.Input), processer.Output, processer.Format.Value, processer.Version.Value);
|
||||
generator = new UrlOpenApiGenerator(new Uri(processer.Input), processer.Output, processer.Format.Value, settings);
|
||||
}
|
||||
|
||||
if (generator.Generate())
|
||||
|
|
|
@ -25,14 +25,38 @@ Output the "JSON" format Open API document;
|
|||
|
||||
Output the "YAML" format Open API document;
|
||||
|
||||
### [--specversion|-s int]
|
||||
### [--keyassegment|-k]
|
||||
|
||||
Indicate which version, either 2 or 3, of the OpenApi specification to output. Only 2 or 3 are supported;
|
||||
Output the document using key-as-segment style URLs.;
|
||||
|
||||
### [--derivedtypesreferencesforresponses|-drs]
|
||||
|
||||
Output the document to expect all derived types in responses.;
|
||||
|
||||
### [--derivedtypesreferencesforrequestbody|-drq]
|
||||
|
||||
Output the document to expect all derived types in request bodies.;
|
||||
|
||||
### [--enablepagination|-p]
|
||||
|
||||
Output the document to expose pagination for collections.;
|
||||
|
||||
### [--enableunqualifiedcall|-u]
|
||||
|
||||
Output the document to use unqualified calls for bound operations.;
|
||||
|
||||
### [--disableschemaexamples|-x]
|
||||
|
||||
Output the document without examples in the schema.;
|
||||
|
||||
### [--yaml|-y]
|
||||
|
||||
Output the "YAML" format Open API document;
|
||||
|
||||
### [--specversion|-s int]
|
||||
|
||||
Indicate which version, either 2 or 3, of the OpenApi specification to output. Only 2 or 3 are supported;
|
||||
|
||||
### [--input|-i file]
|
||||
|
||||
Indicate to where to get CSDL, from file or from Uri.
|
||||
|
@ -44,7 +68,7 @@ Indicate to output file name.
|
|||
|
||||
## Examples
|
||||
|
||||
`OoasUtil.exe -j -s 3 -i http://services.odata.org/TrippinRESTierService -o trip.json`
|
||||
`OoasUtil.exe -j -k -drs -drq -p -u -s 3 -i http://services.odata.org/TrippinRESTierService -o trip.json`
|
||||
|
||||
The content of `trip.json` is similar at https://github.com/xuzhg/OData.OpenAPI/blob/master/Microsoft.OData.OpenAPI/Microsoft.OData.OpenAPI.Tests/Resources/TripService.OpenApi.json
|
||||
|
||||
|
|
|
@ -31,9 +31,10 @@ namespace OoasUtil
|
|||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="target">The output target.</param>
|
||||
public UrlOpenApiGenerator(Uri input, string output, OpenApiFormat format, OpenApiSpecVersion version)
|
||||
: base(output, format, version)
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="settings">Conversion settings.</param>
|
||||
public UrlOpenApiGenerator(Uri input, string output, OpenApiFormat format, OpenApiConvertSettings settings)
|
||||
: base(output, format, settings)
|
||||
{
|
||||
Input = input;
|
||||
}
|
||||
|
@ -58,12 +59,10 @@ namespace OoasUtil
|
|||
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
|
||||
}
|
||||
|
||||
protected override OpenApiConvertSettings GetSettings()
|
||||
protected override void ModifySettings()
|
||||
{
|
||||
return new OpenApiConvertSettings
|
||||
{
|
||||
ServiceRoot = Input
|
||||
};
|
||||
base.ModifySettings();
|
||||
Settings.ServiceRoot = Input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Csdl;
|
||||
|
@ -12,6 +13,8 @@ using Xunit;
|
|||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Microsoft.OData.Edm.Validation;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
|
@ -26,6 +29,8 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
|
||||
public static IEdmModel MultipleInheritanceEdmModel { get; }
|
||||
|
||||
public static IEdmModel InheritanceEdmModelAcrossReferences { get; }
|
||||
|
||||
public static IEdmModel BasicEdmModel { get; }
|
||||
|
||||
public static IEdmModel MultipleSchemasEdmModel { get; }
|
||||
|
@ -46,6 +51,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
ContractServiceModel = LoadEdmModel("Contract.OData.xml");
|
||||
GraphBetaModel = LoadEdmModel("Graph.Beta.OData.xml");
|
||||
MultipleSchemasEdmModel = LoadEdmModel("Multiple.Schema.OData.xml");
|
||||
InheritanceEdmModelAcrossReferences = CreateInheritanceEdmModelAcrossReferences();
|
||||
}
|
||||
|
||||
private static IEdmModel LoadEdmModel(string source)
|
||||
|
@ -160,6 +166,50 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
return model;
|
||||
}
|
||||
|
||||
public static IEdmModel CreateInheritanceEdmModelAcrossReferences()
|
||||
{
|
||||
const string modelText =
|
||||
@"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
|
||||
<edmx:Reference Uri=""subModel.csdl"">
|
||||
<edmx:Include Alias=""subModel"" Namespace=""SubNS"" />
|
||||
</edmx:Reference>
|
||||
<edmx:DataServices>
|
||||
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
|
||||
<EntityType Name=""Customer"" BaseType=""SubNS.CustomerBase"">
|
||||
<Property Name=""Extra"" Type=""Edm.Int32"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
<EntityContainer Name =""Default"">
|
||||
<EntitySet Name=""Customers"" EntityType=""NS.Customer"" />
|
||||
</EntityContainer>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>";
|
||||
const string subModelText =
|
||||
@"<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
|
||||
<edmx:DataServices>
|
||||
<Schema Namespace=""SubNS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
|
||||
<EntityType Name=""CustomerBase"">
|
||||
<Key>
|
||||
<PropertyRef Name=""ID"" />
|
||||
</Key>
|
||||
<Property Name=""ID"" Type=""Edm.Int32"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>";
|
||||
|
||||
IEdmModel model;
|
||||
IEnumerable<EdmError> errors;
|
||||
|
||||
XElement parsed = XElement.Parse(modelText);
|
||||
bool result = CsdlReader.TryParse(parsed.CreateReader(),
|
||||
uri => XElement.Parse(subModelText).CreateReader(),
|
||||
out model,
|
||||
out errors);
|
||||
Assert.True(result);
|
||||
return model;
|
||||
}
|
||||
|
||||
private static IEdmModel CreateEdmModel()
|
||||
{
|
||||
var model = new EdmModel();
|
||||
|
@ -359,12 +409,12 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
|
||||
public static string GetCsdl(IEdmModel model)
|
||||
{
|
||||
string edmx = string.Empty;
|
||||
string edmx = String.Empty;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Encoding = System.Text.Encoding.UTF8;
|
||||
settings.Encoding = Encoding.UTF8;
|
||||
settings.Indent = true;
|
||||
|
||||
using (XmlWriter xw = XmlWriter.Create(sw, settings))
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Csdl;
|
||||
using Microsoft.OData.Edm.Validation;
|
||||
using Microsoft.OpenApi.OData.Tests;
|
||||
using Xunit;
|
||||
|
||||
|
@ -55,5 +59,21 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
|
|||
Assert.Equal(2, baseTypes.Count());
|
||||
Assert.Equal(new[] { subEntityType, baseEntityType }, baseTypes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAllElementsReturnsElementsFromAllModels()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
|
||||
|
||||
// Act
|
||||
var elements = model.GetAllElements();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(elements,
|
||||
e => Assert.Equal("Customer", e.Name),
|
||||
e => Assert.Equal("Default", e.Name),
|
||||
e => Assert.Equal("CustomerBase", e.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -335,6 +335,52 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
}"
|
||||
.ChangeLineBreaks(), json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntityTypeWithCrossReferenceBaseSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
|
||||
ODataContext context = new ODataContext(model, new OpenApiConvertSettings
|
||||
{
|
||||
ShowSchemaExamples = true
|
||||
});
|
||||
IEdmEntityType entity = model.SchemaElements.OfType<IEdmEntityType>().First(t => t.Name == "Customer");
|
||||
Assert.NotNull(entity); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateStructuredTypeSchema(entity);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.True(String.IsNullOrEmpty(schema.Type));
|
||||
|
||||
Assert.NotNull(schema.AllOf);
|
||||
Assert.Null(schema.AnyOf);
|
||||
Assert.Null(schema.OneOf);
|
||||
Assert.Null(schema.Properties);
|
||||
|
||||
Assert.Equal(2, schema.AllOf.Count);
|
||||
var baseSchema = schema.AllOf.First();
|
||||
Assert.NotNull(baseSchema.Reference);
|
||||
Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type);
|
||||
Assert.Equal("SubNS.CustomerBase", baseSchema.Reference.Id);
|
||||
|
||||
var declaredSchema = schema.AllOf.Last();
|
||||
Assert.Equal("object", declaredSchema.Type);
|
||||
Assert.Null(declaredSchema.AllOf);
|
||||
Assert.Null(declaredSchema.AnyOf);
|
||||
Assert.Null(declaredSchema.OneOf);
|
||||
|
||||
Assert.NotNull(declaredSchema.Properties);
|
||||
Assert.Equal(1, declaredSchema.Properties.Count);
|
||||
var property = Assert.Single(declaredSchema.Properties);
|
||||
Assert.Equal("Extra", property.Key);
|
||||
Assert.Equal("integer", property.Value.Type);
|
||||
Assert.Null(property.Value.OneOf);
|
||||
|
||||
Assert.Equal("Customer", declaredSchema.Title);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EnumTypeSchema
|
||||
|
|
|
@ -9,6 +9,7 @@ using Microsoft.OData.Edm;
|
|||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.OData.Edm;
|
||||
using Microsoft.OpenApi.OData.Properties;
|
||||
using Microsoft.OpenApi.OData.Tests;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.PathItem.Tests
|
||||
|
@ -75,6 +76,31 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
|
|||
pathItem.Operations.Select(o => o.Key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntityPathItemReturnsCorrectPathItemWithReferences()
|
||||
{
|
||||
// Test that references don't disturb the paths.
|
||||
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
|
||||
Assert.NotNull(entitySet); // guard
|
||||
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
|
||||
|
||||
// Act
|
||||
var pathItem = _pathItemHandler.CreatePathItem(context, path);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(pathItem);
|
||||
|
||||
Assert.NotNull(pathItem.Operations);
|
||||
Assert.NotEmpty(pathItem.Operations);
|
||||
Assert.Equal(3, pathItem.Operations.Count);
|
||||
Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete },
|
||||
pathItem.Operations.Select(o => o.Key));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })]
|
||||
[InlineData(false, new OperationType[] { OperationType.Patch, OperationType.Delete })]
|
||||
|
|
Loading…
Reference in a new issue