diff --git a/src/ApiGenerator/ApiGenerator.csproj b/src/ApiGenerator/ApiGenerator.csproj
index 5204b3a3d0..ea6d9cc7eb 100644
--- a/src/ApiGenerator/ApiGenerator.csproj
+++ b/src/ApiGenerator/ApiGenerator.csproj
@@ -13,6 +13,7 @@
+
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Methods/BoundFluentMethod.cs b/src/ApiGenerator/Domain/Code/HighLevel/Methods/BoundFluentMethod.cs
index 7e005f027f..54e96d8645 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Methods/BoundFluentMethod.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Methods/BoundFluentMethod.cs
@@ -30,17 +30,18 @@
using System.Linq;
using ApiGenerator.Configuration;
using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
-namespace ApiGenerator.Domain.Code.HighLevel.Methods
+namespace ApiGenerator.Domain.Code.HighLevel.Methods
{
public class BoundFluentMethod : FluentSyntaxBase
{
- public BoundFluentMethod(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary)
- : base(names, parts, selectorIsOptional, link, summary) { }
+ public BoundFluentMethod(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary, Deprecation deprecated, Version versionAdded)
+ : base(names, parts, selectorIsOptional, link, summary, deprecated, versionAdded) { }
private string DescriptorTypeParams => string.Join(", ", CsharpNames.DescriptorGenerics
.Select(e => CsharpNames.DescriptorBoundDocumentGeneric));
-
+
private string RequestTypeParams => string.Join(", ", CsharpNames.SplitGeneric(CsharpNames.GenericsDeclaredOnRequest)
.Select(e => CsharpNames.DescriptorBoundDocumentGeneric));
@@ -48,17 +49,17 @@ public BoundFluentMethod(CsharpNames names, IReadOnlyCollection parts,
|| !CodeConfiguration.GenericOnlyInterfaces.Contains(CsharpNames.RequestInterfaceName)
? CsharpNames.RequestInterfaceName
: $"{CsharpNames.RequestInterfaceName}<{RequestTypeParams}>";
-
+
public override string DescriptorName => $"{CsharpNames.DescriptorName}<{DescriptorTypeParams}>";
public override string GenericWhereClause => $"where {CsharpNames.DescriptorBoundDocumentGeneric} : class";
public override string MethodGenerics => $"<{CsharpNames.DescriptorBoundDocumentGeneric}>";
-
- public override string RequestMethodGenerics => !string.IsNullOrWhiteSpace(RequestTypeParams)
+
+ public override string RequestMethodGenerics => !string.IsNullOrWhiteSpace(RequestTypeParams)
? $"<{RequestTypeParams}>"
: base.RequestMethodGenerics;
-
+
public override string Selector => $"Func<{DescriptorName}, {SelectorReturn}>";
-
+
}
}
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentMethod.cs b/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentMethod.cs
index 07c5ccd5a9..fe7f3a3690 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentMethod.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentMethod.cs
@@ -29,13 +29,14 @@
using System.Collections.Generic;
using System.Linq;
using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
-namespace ApiGenerator.Domain.Code.HighLevel.Methods
+namespace ApiGenerator.Domain.Code.HighLevel.Methods
{
public class FluentMethod : FluentSyntaxBase
{
- public FluentMethod(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary)
- : base(names, parts, selectorIsOptional, link, summary) { }
+ public FluentMethod(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary, Deprecation deprecated, Version versionAdded)
+ : base(names, parts, selectorIsOptional, link, summary, deprecated, versionAdded) { }
public override string GenericWhereClause =>
string.Join(" ", CsharpNames.HighLevelDescriptorMethodGenerics
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentSyntaxBase.cs b/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentSyntaxBase.cs
index abff18c282..e3f9d02765 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentSyntaxBase.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Methods/FluentSyntaxBase.cs
@@ -30,15 +30,16 @@
using System.Linq;
using ApiGenerator.Configuration;
using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
-namespace ApiGenerator.Domain.Code.HighLevel.Methods
+namespace ApiGenerator.Domain.Code.HighLevel.Methods
{
public abstract class FluentSyntaxBase : MethodSyntaxBase
{
private readonly bool _selectorIsOptional;
- protected FluentSyntaxBase(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary)
- : base(names, link, summary) =>
+ protected FluentSyntaxBase(CsharpNames names, IReadOnlyCollection parts, bool selectorIsOptional, string link, string summary, Deprecation deprecated, Version versionAdded)
+ : base(names, link, summary, deprecated, versionAdded) =>
(UrlParts, _selectorIsOptional) = (CreateDescriptorArgs(parts), selectorIsOptional);
private IReadOnlyCollection UrlParts { get; }
@@ -61,7 +62,7 @@ protected FluentSyntaxBase(CsharpNames names, IReadOnlyCollection parts
CodeConfiguration.GenericOnlyInterfaces.Contains(CsharpNames.RequestInterfaceName)
? CsharpNames.GenericsDeclaredOnRequest
: DescriptorGenerics;
-
+
public virtual string RequestMethodGenerics =>
CodeConfiguration.GenericOnlyInterfaces.Contains(CsharpNames.RequestInterfaceName)
? CsharpNames.GenericsDeclaredOnRequest
@@ -74,11 +75,11 @@ protected FluentSyntaxBase(CsharpNames names, IReadOnlyCollection parts
private List CreateDescriptorArgs(IReadOnlyCollection parts)
{
var requiredParts = parts.Where(p => p.Required).ToList();
-
+
//Many api's return ALOT of information by default e.g get_alias or get_mapping
//the client methods that take a descriptor default to forcing a choice on the user.
//except for cat api's where the amount of information returned is manageable
-
+
var willInferFromDocument = CsharpNames.GenericsDeclaredOnDescriptor?.Contains("Document") ?? false;
if (!requiredParts.Any() && CsharpNames.Namespace != "Cat")
{
@@ -113,15 +114,15 @@ private List CreateDescriptorArgs(IReadOnlyCollection parts)
}
private bool IsDocumentRequest => CodeConfiguration.DocumentRequests.Contains(CsharpNames.RequestInterfaceName);
- private string GenericFirstArgument =>
+ private string GenericFirstArgument =>
CsharpNames.GenericsDeclaredOnDescriptor.Replace("<", "").Replace(">", "").Split(",").First().Trim();
-
+
public string DescriptorArguments()
{
string codeArgs;
if (CodeConfiguration.DescriptorConstructors.TryGetValue(CsharpNames.DescriptorName, out codeArgs))
codeArgs += ",";
-
+
if (!UrlParts.Any()) return codeArgs;
string Optional(UrlPart p) => !p.Required && SelectorIsOptional ? " = null" : string.Empty;
@@ -136,17 +137,17 @@ public string SelectorArguments()
codeArgs = string.Join(", ", codeArgs.Split(',').Select(a=>a.Split(' ').Last()));
return codeArgs;
}
-
+
var parts = UrlParts.Where(p => p.Required).ToList();
if (!parts.Any()) return null;
string ToArg(UrlPart p)
{
if (IsDocumentRequest) return "documentWithId: document";
-
+
if (p.HighLevelTypeName.StartsWith("DocumentPath"))
return "documentWithId: id?.Document, index: id?.Self?.Index, id: id?.Self?.Id";
-
+
return $"{p.Name.ToCamelCase()}: {p.Name.ToCamelCase()}";
}
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Methods/InitializerMethod.cs b/src/ApiGenerator/Domain/Code/HighLevel/Methods/InitializerMethod.cs
index d47228b3ce..f0f048e494 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Methods/InitializerMethod.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Methods/InitializerMethod.cs
@@ -28,12 +28,14 @@
using System.Linq;
using ApiGenerator.Configuration;
+using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
namespace ApiGenerator.Domain.Code.HighLevel.Methods
{
public class InitializerMethod : MethodSyntaxBase
{
- public InitializerMethod(CsharpNames names, string link, string summary) : base(names, link, summary) { }
+ public InitializerMethod(CsharpNames names, string link, string summary, Deprecation deprecated, Version versionAdded) : base(names, link, summary, deprecated, versionAdded) { }
public string MethodName => CsharpNames.MethodName;
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Methods/MethodSyntaxBase.cs b/src/ApiGenerator/Domain/Code/HighLevel/Methods/MethodSyntaxBase.cs
index 5e27c6d8e2..a0b1f329df 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Methods/MethodSyntaxBase.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Methods/MethodSyntaxBase.cs
@@ -26,17 +26,24 @@
* under the License.
*/
+using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
+
namespace ApiGenerator.Domain.Code.HighLevel.Methods
{
public abstract class MethodSyntaxBase
{
- protected MethodSyntaxBase(CsharpNames names, string link, string summary) =>
- (CsharpNames, DocumentationLink, XmlDocSummary) = (names, link, summary);
+ protected MethodSyntaxBase(CsharpNames names, string link, string summary, Deprecation deprecated, Version versionAdded) =>
+ (CsharpNames, DocumentationLink, XmlDocSummary, Deprecated, VersionAdded) = (names, link, summary, deprecated, versionAdded);
public string DocumentationLink { get; }
public string XmlDocSummary { get; }
+ public Deprecation Deprecated { get; }
+
+ public Version VersionAdded { get; set; }
+
protected CsharpNames CsharpNames { get; }
public bool InterfaceResponse => ResponseName.StartsWith("ISearchResponse<");
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Requests/Constructor.cs b/src/ApiGenerator/Domain/Code/HighLevel/Requests/Constructor.cs
index a46a85660e..fcf1562b36 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Requests/Constructor.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Requests/Constructor.cs
@@ -127,7 +127,7 @@ string generic
Parameterless = true,
Generated = $"protected {typeName}() : base()",
Description =
- $"///Used for serialization purposes, making sure we have a parameterless constructor{Indent}[SerializationConstructor]",
+ $"/// Used for serialization purposes, making sure we have a parameterless constructor{Indent}[SerializationConstructor]",
});
return constructors;
}
diff --git a/src/ApiGenerator/Domain/Code/HighLevel/Requests/DescriptorPartialImplementation.cs b/src/ApiGenerator/Domain/Code/HighLevel/Requests/DescriptorPartialImplementation.cs
index 3039482559..3f5a39882d 100644
--- a/src/ApiGenerator/Domain/Code/HighLevel/Requests/DescriptorPartialImplementation.cs
+++ b/src/ApiGenerator/Domain/Code/HighLevel/Requests/DescriptorPartialImplementation.cs
@@ -30,7 +30,7 @@
using System.Linq;
using ApiGenerator.Domain.Specification;
-namespace ApiGenerator.Domain.Code.HighLevel.Requests
+namespace ApiGenerator.Domain.Code.HighLevel.Requests
{
public class DescriptorPartialImplementation
{
@@ -41,7 +41,7 @@ public class DescriptorPartialImplementation
public IReadOnlyCollection Paths { get; set; }
public IReadOnlyCollection Params { get; set; }
public bool HasBody { get; set; }
-
+
public IEnumerable GetFluentRouteSetters()
{
var setters = new List();
@@ -67,26 +67,26 @@ public IEnumerable GetFluentRouteSetters()
var code =
$"public {returnType} {p.InterfaceName}({p.HighLevelTypeName} {paramName}) => Assign({paramName}, (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", {routeValue}));";
- var xmlDoc = $"///{p.Description}";
+ var xmlDoc = $"/// {p.Description}";
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
if (paramName == "index")
{
code = $"public {returnType} {p.InterfaceName}() where TOther : class ";
code += $"=> Assign(typeof(TOther), (a,v)=>a.RouteValues.{routeSetter}(\"{p.Name}\", ({p.HighLevelTypeName})v));";
- xmlDoc = $"///a shortcut into calling {p.InterfaceName}(typeof(TOther))";
+ xmlDoc = $"/// a shortcut into calling {p.InterfaceName}(typeof(TOther))";
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
}
if (paramName == "index" && p.Type == "list")
{
code = $"public {returnType} AllIndices() => Index(Indices.All);";
- xmlDoc = $"///A shortcut into calling Index(Indices.All)";
+ xmlDoc = $"/// A shortcut into calling Index(Indices.All)";
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
}
if (paramName == "fields" && p.Type == "list")
{
code = $"public {returnType} Fields(params Expression>[] fields) ";
code += $"=> Assign(fields, (a,v)=>a.RouteValues.{routeSetter}(\"fields\", (Fields)v));";
- xmlDoc = $"///{p.Description}";
+ xmlDoc = $"/// {p.Description}";
setters.Add(new FluentRouteSetter { Code = code, XmlDoc = xmlDoc });
}
}
diff --git a/src/ApiGenerator/Domain/Code/LowLevel/LowLevelClientMethod.cs b/src/ApiGenerator/Domain/Code/LowLevel/LowLevelClientMethod.cs
index f00f74f9e5..a81e269163 100644
--- a/src/ApiGenerator/Domain/Code/LowLevel/LowLevelClientMethod.cs
+++ b/src/ApiGenerator/Domain/Code/LowLevel/LowLevelClientMethod.cs
@@ -30,6 +30,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using ApiGenerator.Domain.Specification;
+using SemanticVersioning;
namespace ApiGenerator.Domain.Code.LowLevel
{
@@ -44,35 +45,31 @@ public class LowLevelClientMethod
public string PerPathMethodName { get; set; }
public string HttpMethod { get; set; }
- public DeprecatedPath DeprecatedPath { get; set; }
+ public Deprecation Deprecation { get; set; }
public UrlInformation Url { get; set; }
public bool HasBody { get; set; }
public IEnumerable Parts { get; set; }
public string Path { get; set; }
+ public Version VersionAdded { get; set; }
public string UrlInCode
{
get
{
- string Evaluator(Match m)
- {
-
- var arg = m.Groups[^1].Value.ToCamelCase();
- return $"{{{arg}:{arg}}}";
- }
-
- var url = Path.TrimStart('/');
- var options = Url.OriginalParts?.Select(p => p.Key) ?? Enumerable.Empty();
+ var url = Path.TrimStart('/');
+ var options = Url.AllPaths.SelectMany(p => p.Parts).Select(p => p.Name).Distinct();
var pattern = string.Join("|", options);
var urlCode = $"\"{url}\"";
- if (Path.Contains("{"))
- {
- var patchedUrl = Regex.Replace(url, "{(" + pattern + ")}", Evaluator);
- urlCode = $"Url($\"{patchedUrl}\")";
- }
- return urlCode;
+ if (!Path.Contains('{')) return urlCode;
+
+ var patchedUrl = Regex.Replace(url, "{(" + pattern + ")}", m =>
+ {
+ var arg = m.Groups[^1].Value.ToCamelCase();
+ return $"{{{arg}:{arg}}}";
+ });
+ return $"Url($\"{patchedUrl}\")";
}
}
diff --git a/src/ApiGenerator/Domain/RestApiSpec.cs b/src/ApiGenerator/Domain/RestApiSpec.cs
index c474fa71d6..042910cefb 100644
--- a/src/ApiGenerator/Domain/RestApiSpec.cs
+++ b/src/ApiGenerator/Domain/RestApiSpec.cs
@@ -66,7 +66,7 @@ public IEnumerable EnumsInTheSpec
var urlParameterEnums = Endpoints
.Values
.SelectMany(e => e.Url.Params.Values)
- .Where(p => p.Options != null && p.Options.Any())
+ .Where(p => !p.Skip && p.Options != null && p.Options.Any())
.Select(p => new EnumDescription
{
Name = p.ClsName,
diff --git a/src/ApiGenerator/Domain/Specification/ApiEndpoint.cs b/src/ApiGenerator/Domain/Specification/ApiEndpoint.cs
index 8ff2f8c41f..f22c15731f 100644
--- a/src/ApiGenerator/Domain/Specification/ApiEndpoint.cs
+++ b/src/ApiGenerator/Domain/Specification/ApiEndpoint.cs
@@ -33,6 +33,7 @@
using ApiGenerator.Domain.Code.HighLevel.Methods;
using ApiGenerator.Domain.Code.HighLevel.Requests;
using ApiGenerator.Domain.Code.LowLevel;
+using SemanticVersioning;
namespace ApiGenerator.Domain.Specification
{
@@ -78,7 +79,7 @@ public class ApiEndpoint
CsharpNames = CsharpNames,
OfficialDocumentationLink = OfficialDocumentationLink?.Url,
Stability = Stability,
- Paths = Url.Paths,
+ Paths = Url.Paths.ToList(),
Parts = Url.Parts,
Params = ParamsToGenerate.ToList(),
Constructors = Constructor.RequestConstructors(CsharpNames, Url, inheritsFromPlainRequestBase: true).ToList(),
@@ -91,7 +92,7 @@ public class ApiEndpoint
CsharpNames = CsharpNames,
OfficialDocumentationLink = OfficialDocumentationLink?.Url,
Constructors = Constructor.DescriptorConstructors(CsharpNames, Url).ToList(),
- Paths = Url.Paths,
+ Paths = Url.Paths.ToList(),
Parts = Url.Parts,
Params = ParamsToGenerate.ToList(),
HasBody = Body != null,
@@ -117,24 +118,45 @@ public class ApiEndpoint
public string HighLevelMethodXmlDocDescription =>
$"{PreferredHttpMethod} request to the {Name} API, read more about this API online:";
- public HighLevelModel HighLevelModel => new HighLevelModel
- {
+ private bool BodyIsOptional => Body is not { Required: true } || HttpMethods.Contains("GET");
+
+ private Deprecation Deprecated =>
+ !Url.Paths.Any() && Url.AllPaths.Count > 0
+ ? Url.DeprecatedPaths
+ .Select(p => p.Deprecation)
+ .MaxBy(d => d.Version)
+ : null;
+
+ private Version VersionAdded =>
+ Url.AllPaths
+ .Select(p => p.VersionAdded)
+ .Where(v => v != null)
+ .Min();
+
+ public HighLevelModel HighLevelModel => new()
+ {
CsharpNames = CsharpNames,
Fluent = new FluentMethod(CsharpNames, Url.Parts,
- selectorIsOptional: Body == null || !Body.Required || HttpMethods.Contains("GET"),
+ selectorIsOptional: BodyIsOptional,
link: OfficialDocumentationLink?.Url,
- summary: HighLevelMethodXmlDocDescription
+ summary: HighLevelMethodXmlDocDescription,
+ deprecated: Deprecated,
+ versionAdded: VersionAdded
),
FluentBound = !CsharpNames.DescriptorBindsOverMultipleDocuments
? null
: new BoundFluentMethod(CsharpNames, Url.Parts,
- selectorIsOptional: Body == null || !Body.Required || HttpMethods.Contains("GET"),
+ selectorIsOptional: BodyIsOptional,
link: OfficialDocumentationLink?.Url,
- summary: HighLevelMethodXmlDocDescription
+ summary: HighLevelMethodXmlDocDescription,
+ deprecated: Deprecated,
+ versionAdded: VersionAdded
),
Initializer = new InitializerMethod(CsharpNames,
link: OfficialDocumentationLink?.Url,
- summary: HighLevelMethodXmlDocDescription
+ summary: HighLevelMethodXmlDocDescription,
+ deprecated: Deprecated,
+ versionAdded: VersionAdded
)
};
@@ -153,7 +175,7 @@ public IReadOnlyCollection LowLevelClientMethods
Generator.ApiGenerator.Warnings.Add($"API '{Name}' has no documentation");
var httpMethod = PreferredHttpMethod;
- foreach (var path in Url.PathsWithDeprecations)
+ foreach (var path in Url.AllPaths)
{
var methodName = CsharpNames.PerPathMethodName(path.Path);
var parts = new List(path.Parts);
@@ -183,11 +205,12 @@ public IReadOnlyCollection LowLevelClientMethods
HttpMethod = httpMethod,
OfficialDocumentationLink = OfficialDocumentationLink?.Url,
Stability = Stability,
- DeprecatedPath = path.Deprecation,
+ Deprecation = path.Deprecation,
Path = path.Path,
Parts = parts,
Url = Url,
- HasBody = Body != null
+ HasBody = Body != null,
+ VersionAdded = path.VersionAdded,
};
_lowLevelClientMethods.Add(apiMethod);
}
diff --git a/src/ApiGenerator/Domain/Specification/Deprecation.cs b/src/ApiGenerator/Domain/Specification/Deprecation.cs
new file mode 100644
index 0000000000..96ac03c7d7
--- /dev/null
+++ b/src/ApiGenerator/Domain/Specification/Deprecation.cs
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: Apache-2.0
+*
+* The OpenSearch Contributors require contributions made to
+* this file be licensed under the Apache-2.0 license or a
+* compatible open source license.
+*/
+/*
+* Modifications Copyright OpenSearch Contributors. See
+* GitHub history for details.
+*
+* Licensed to Elasticsearch B.V. under one or more contributor
+* license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright
+* ownership. Elasticsearch B.V. licenses this file to you under
+* the Apache License, Version 2.0 (the "License"); you may
+* not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+namespace ApiGenerator.Domain.Specification;
+
+public class Deprecation
+{
+ public string Version { get; set; }
+
+ public string Description { get; set; }
+
+ public override string ToString() =>
+ (!string.IsNullOrEmpty(Version), !string.IsNullOrEmpty(Description)) switch
+ {
+ (true, true) => $"Deprecated as of: {Version}, reason: {Description}",
+ (true, false) => $"Deprecated as of: {Version}",
+ (false, true) => $"reason: {Description}",
+ _ => "deprecated"
+ };
+}
diff --git a/src/ApiGenerator/Domain/Specification/QueryParameters.cs b/src/ApiGenerator/Domain/Specification/QueryParameters.cs
index f77b851068..71fae53ebd 100644
--- a/src/ApiGenerator/Domain/Specification/QueryParameters.cs
+++ b/src/ApiGenerator/Domain/Specification/QueryParameters.cs
@@ -30,6 +30,7 @@
using System.Collections.Generic;
using System.Linq;
using ApiGenerator.Generator;
+using Version = SemanticVersioning.Version;
namespace ApiGenerator.Domain.Specification
{
@@ -45,7 +46,7 @@ public class QueryParameters
public string Description { get; set; }
- public string VersionAdded { get; set; }
+ public Version VersionAdded { get; set; }
public IEnumerable DescriptionHighLevel
{
@@ -97,27 +98,13 @@ public IEnumerable DescriptionHighLevel
public string Obsolete
{
- get
- {
- if (!string.IsNullOrEmpty(_obsolete)) return _obsolete;
- if (Deprecated != null)
- {
- if (!string.IsNullOrEmpty(Deprecated.Version) && !string.IsNullOrEmpty(Deprecated.Description))
- return $"Deprecated as of: {Deprecated.Version}, reason: {Deprecated.Description}";
- if (!string.IsNullOrEmpty(Deprecated.Version))
- return $"Deprecated as of: {Deprecated.Version}";
- if (!string.IsNullOrEmpty(Deprecated.Description))
- return $"reason: {Deprecated.Description}";
-
- return "deprecated";
- }
-
- return null;
- }
- set => _obsolete = value;
+ get => !string.IsNullOrEmpty(_obsolete)
+ ? _obsolete
+ : Deprecated?.ToString();
+ set => _obsolete = value;
}
- public QueryParameterDeprecation Deprecated { get; set; }
+ public Deprecation Deprecated { get; set; }
public IEnumerable Options { get; set; }
public string QueryStringKey { get; set; }
@@ -193,14 +180,7 @@ public string TypeLowLevel
}
- public string InitializerGenerator(string @namespace, string type, string name, string key, string setter, string versionAdded, params string[] doc) =>
+ public string InitializerGenerator(string @namespace, string type, string name, string key, string setter, Version versionAdded, params string[] doc) =>
CodeGenerator.Property(@namespace, type, name, key, setter, Obsolete, versionAdded, doc);
}
-
- public class QueryParameterDeprecation
- {
- public string Version { get; set; }
-
- public string Description { get; set; }
- }
}
diff --git a/src/ApiGenerator/Domain/Specification/UrlInformation.cs b/src/ApiGenerator/Domain/Specification/UrlInformation.cs
index e64e36d2ff..34f7c55591 100644
--- a/src/ApiGenerator/Domain/Specification/UrlInformation.cs
+++ b/src/ApiGenerator/Domain/Specification/UrlInformation.cs
@@ -26,9 +26,7 @@
* under the License.
*/
-using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Linq;
namespace ApiGenerator.Domain.Specification
@@ -39,80 +37,10 @@ public class UrlInformation
{
public IDictionary Params { get; set; } = new SortedDictionary();
- public IList OriginalPaths { get; set; } = new List();
-
- public IDictionary OriginalParts { get; set; }
-
- public IList DeprecatedPaths { get; set; } = new List();
-
- private List _paths;
- public IReadOnlyCollection Paths
- {
- get
- {
- if (_paths != null && _paths.Count > 0) return _paths;
-
- _paths = OriginalPaths.Select(p => new UrlPath(p, OriginalParts)).ToList();
- return _paths;
- }
- }
-
- private List _pathsWithDeprecation;
- public IReadOnlyCollection PathsWithDeprecations
- {
- get
- {
- if (_pathsWithDeprecation != null && _pathsWithDeprecation.Count > 0) return _pathsWithDeprecation;
-
- var paths = Paths ?? new UrlPath[] {};
- if (DeprecatedPaths == null || DeprecatedPaths.Count == 0) return Paths;
- if (OriginalParts == null) return Paths;
-
- //some deprecated paths describe aliases to the canonical using the same path e.g
- // PUT /{index}/_mapping/{type}
- // PUT /{index}/{type}/_mappings
- //
- //The following routine dedups these occasions and prefers either the canonical path
- //or the first duplicate deprecated path
-
- var canonicalPartNameLookup = paths.Select(path => new HashSet(path.Parts.Select(p => p.Name))).ToList();
- var withoutDeprecatedAliases = DeprecatedPaths
- .Select(deprecatedPath => new
- {
- deprecatedPath,
- parts = new HashSet(OriginalParts.Keys.Where(k => deprecatedPath.Path.Contains($"{{{k}}}")))
- })
- .GroupBy(t => t.parts, HashSet.CreateSetComparer())
- .Where(grouped => !canonicalPartNameLookup.Any(set => set.SetEquals(grouped.Key)))
- .Select(grouped => grouped.First().deprecatedPath);
-
- _pathsWithDeprecation = paths
- .Concat(withoutDeprecatedAliases.Select(p => new UrlPath(p, OriginalParts, Paths)))
- .ToList();
-
- // now, check for and prefer deprecated URLs
-
- var finalPathsWithDeprecations = new List(_pathsWithDeprecation.Count);
-
- foreach (var path in _pathsWithDeprecation)
- {
- if (path.Deprecation is null &&
- DeprecatedPaths.SingleOrDefault(p => p.Path.Equals(path.Path, StringComparison.OrdinalIgnoreCase)) is { } match)
- {
- finalPathsWithDeprecations.Add(new UrlPath(match, OriginalParts, Paths));
- }
- else
- {
- finalPathsWithDeprecations.Add(path);
- }
- }
-
- _pathsWithDeprecation = finalPathsWithDeprecations;
-
- return _pathsWithDeprecation;
- }
- }
+ public IEnumerable Paths => AllPaths.Where(p => p.Deprecation == null);
+ public IEnumerable DeprecatedPaths => AllPaths.Where(p => p.Deprecation != null);
+ public IList AllPaths = new List();
public IReadOnlyCollection Parts => Paths
.SelectMany(p => p.Parts)
@@ -127,7 +55,7 @@ public IReadOnlyCollection PathsWithDeprecations
public bool IsDocumentApi => IsADocumentRoute(Parts);
public static bool IsADocumentRoute(IReadOnlyCollection parts) =>
- parts.Count() == DocumentApiParts.Length
+ parts.Count == DocumentApiParts.Length
&& parts.All(p => DocumentApiParts.Contains(p.Name));
@@ -136,8 +64,8 @@ public bool TryGetDocumentApiPath(out UrlPath path)
path = null;
if (!IsDocumentApi) return false;
- var mostVerbosePath = _paths.OrderByDescending(p => p.Parts.Count()).First();
- path = new UrlPath(mostVerbosePath.Path, OriginalParts, mostVerbosePath.Parts);
+ var mostVerbosePath = Paths.OrderByDescending(p => p.Parts.Count).First();
+ path = new UrlPath(mostVerbosePath.Path, mostVerbosePath.Parts, mostVerbosePath.Deprecation, mostVerbosePath.VersionAdded, mostVerbosePath.Parts);
return true;
}
}
diff --git a/src/ApiGenerator/Domain/Specification/UrlPart.cs b/src/ApiGenerator/Domain/Specification/UrlPart.cs
index f0f0c27bbb..08a3d02089 100644
--- a/src/ApiGenerator/Domain/Specification/UrlPart.cs
+++ b/src/ApiGenerator/Domain/Specification/UrlPart.cs
@@ -30,16 +30,6 @@
namespace ApiGenerator.Domain.Specification
{
-
- // Rename this type to Deprecation and remove Path duplication
- public class DeprecatedPath
- {
- public string Version { get; set; }
- public string Path { get; set; }
- public string Description { get; set; }
- }
-
-
public class UrlPart
{
private string _description;
@@ -146,30 +136,23 @@ public string Description
set => _description = CleanUpDescription(value);
}
- public string InterfaceName
- {
- get
- {
- switch (Name)
- {
- case "repository": return "RepositoryName";
- default: return Name.ToPascalCase();
- }
- }
- }
+ public string InterfaceName =>
+ Name switch
+ {
+ "repository" => "RepositoryName",
+ _ => Name.ToPascalCase()
+ };
- public string Name { get; set; }
+ public string Name { get; set; }
public string NameAsArgument => Name.ToCamelCase();
public IEnumerable Options { get; set; }
public bool Required { get; set; }
public bool Deprecated { get; set; }
public string Type { get; set; }
- private string CleanUpDescription(string value)
- {
- if (string.IsNullOrWhiteSpace(value)) return value;
-
- return value.Replace("use `_all` or empty string", "use the special string `_all` or Indices.All");
- }
- }
+ private static string CleanUpDescription(string value) =>
+ string.IsNullOrWhiteSpace(value)
+ ? value
+ : value.Replace("use `_all` or empty string", "use the special string `_all` or Indices.All");
+ }
}
diff --git a/src/ApiGenerator/Domain/Specification/UrlPath.cs b/src/ApiGenerator/Domain/Specification/UrlPath.cs
index b1546f4f6e..63f215ea07 100644
--- a/src/ApiGenerator/Domain/Specification/UrlPath.cs
+++ b/src/ApiGenerator/Domain/Specification/UrlPath.cs
@@ -26,50 +26,28 @@
* under the License.
*/
-using System;
using System.Collections.Generic;
using System.Linq;
+using SemanticVersioning;
-namespace ApiGenerator.Domain.Specification
+namespace ApiGenerator.Domain.Specification
{
public class UrlPath
{
- private readonly List _additionalPartsForConstructor;
+ private readonly IList _additionalPartsForConstructor;
public string Path { get; }
- public DeprecatedPath Deprecation { get; }
+ public Deprecation Deprecation { get; }
+ public Version VersionAdded { get; }
+ public IList Parts { get; }
-
- public List Parts { get; }
-
- //TODO mark the parts that are deprecated
- public UrlPath(DeprecatedPath path, IDictionary originalParts, IReadOnlyCollection allNonDeprecatedPaths)
- : this(path.Path, originalParts)
- {
- Deprecation = path;
- foreach (var part in Parts)
- {
- if (!part.Deprecated && !allNonDeprecatedPaths.Any(p => p.Path.Contains($"{{{part.Name}}}")))
- part.Deprecated = true;
- }
- }
- public UrlPath(string path, IDictionary allParts, List additionalPartsForConstructor = null)
+ public UrlPath(string path, IList parts, Deprecation deprecation, Version versionAdded, IList additionalPartsForConstructor = null)
{
_additionalPartsForConstructor = additionalPartsForConstructor ?? new List();
Path = LeadingBackslash(path);
- if (allParts == null)
- {
- Parts = new List();
- return;
- }
- var parts =
- from p in allParts
- //so deliciously side effect-y but at least its more isolated then in ApiEndpoint.CsharpMethods
- let name = p.Value.Name = p.Key
- where path.Contains($"{{{name}}}")
- orderby path.IndexOf($"{{{name}}}", StringComparison.Ordinal)
- select p.Value;
- Parts = parts.ToList();
- }
+ Parts = parts;
+ Deprecation = deprecation;
+ VersionAdded = versionAdded;
+ }
public string ConstructorArguments => string.Join(", ", Parts.Select(p => $"{p.HighLevelTypeName} {p.NameAsArgument}"));
public string RequestBaseArguments =>
@@ -95,7 +73,7 @@ public string DocumentPathConstructorArgument(string generic) => string.Join(",
public string GetXmlDocs(string indent, bool skipResolvable = false, bool documentConstructor = false)
{
- var doc = $@"///{Path}";
+ var doc = $@"/// {Path}";
var parts = Parts.Where(p => !skipResolvable || !ResolvabeFromT.Contains(p.Name)).ToList();
if (!parts.Any()) return doc;
@@ -112,7 +90,7 @@ string GetDescription(UrlPart p)
}
}
- private string P(string name, string description) => $"///{description}";
+ private string P(string name, string description) => $"/// {description}";
private string LeadingBackslash(string p) => p.StartsWith("/") ? p : $"/{p}";
}
diff --git a/src/ApiGenerator/Extensions.cs b/src/ApiGenerator/Extensions.cs
index f61b107fe7..9484b5b428 100644
--- a/src/ApiGenerator/Extensions.cs
+++ b/src/ApiGenerator/Extensions.cs
@@ -71,5 +71,8 @@ public static string SplitPascalCase(this string s) =>
public static bool IsNullOrEmpty(this string s) =>
string.IsNullOrEmpty(s);
+
+ public static void SortBy(this List list, Func selector) =>
+ list.Sort((a, b) => Comparer.Default.Compare(selector(a), selector(b)));
}
}
diff --git a/src/ApiGenerator/Generator/ApiEndpointFactory.cs b/src/ApiGenerator/Generator/ApiEndpointFactory.cs
index a8640adbe5..f7827792c5 100644
--- a/src/ApiGenerator/Generator/ApiEndpointFactory.cs
+++ b/src/ApiGenerator/Generator/ApiEndpointFactory.cs
@@ -31,6 +31,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Net.Mime;
+using System.Text.RegularExpressions;
using ApiGenerator.Configuration;
using ApiGenerator.Configuration.Overrides;
using ApiGenerator.Domain;
@@ -39,6 +40,8 @@
using NJsonSchema;
using NJsonSchema.References;
using NSwag;
+using SemanticVersioning;
+using Version = SemanticVersioning.Version;
namespace ApiGenerator.Generator
{
@@ -50,63 +53,103 @@ public static ApiEndpoint From(string name, List<(string HttpPath, OpenApiPathIt
var methodName = tokens[^1];
var ns = tokens.Length > 1 ? tokens[0] : null;
- var urlInfo = new UrlInformation();
- HashSet requiredPathParams = null;
- var allPathParams = new List();
+ HashSet requiredPathParts = null;
+ var allParts = new Dictionary();
+ var canonicalPaths = new Dictionary, UrlPath>(HashSet.CreateSetComparer());
+ var deprecatedPaths = new Dictionary, UrlPath>(HashSet.CreateSetComparer());
+ var overloads = new List<(UrlPath Path, List<(string From, string To)> Renames)>();
foreach (var (httpPath, path, _, operation) in variants.DistinctBy(v => v.HttpPath))
- {
- if (!operation.IsDeprecated)
- urlInfo.OriginalPaths.Add(httpPath);
- else
- {
- urlInfo.DeprecatedPaths.Add(new DeprecatedPath
- {
- Path = httpPath,
- Version = operation.GetExtension("x-version-deprecated") as string,
- Description = operation.GetExtension("x-deprecation-message") as string
- });
- }
-
- var pathParams = path.Parameters
- .Concat(operation.Parameters)
- .Where(p => p.Kind == OpenApiParameterKind.Path)
- .ToList();
-
- foreach (var overloadedParam in pathParams.Where(p => p.Schema.XOverloadedParam() != null))
+ {
+ var parts = new List();
+ var partNames = new HashSet();
+ var overloadedParts = new List<(string From, string To)>();
+
+ foreach (var param in path.Parameters
+ .Concat(operation.Parameters)
+ .Where(p => p.Kind == OpenApiParameterKind.Path))
{
- urlInfo.OriginalPaths.Add(httpPath.Replace(
- $"{{{overloadedParam.Name}}}",
- $"{{{overloadedParam.Schema.XOverloadedParam()}}}"
- ));
+ var partName = param.Name;
+ if (!allParts.TryGetValue(partName, out var part))
+ {
+ part = allParts[partName] = new UrlPart
+ {
+ ClrTypeNameOverride = null,
+ Deprecated = param.IsDeprecated,
+ Description = param.Description,
+ Name = partName,
+ Type = GetOpenSearchType(param.Schema),
+ Options = GetEnumOptions(param.Schema)
+ };
+ }
+ partNames.Add(partName);
+ parts.Add(part);
+
+ if (param.Schema.XOverloadedParam() is {} overloadedParam) overloadedParts.Add((partName, overloadedParam));
}
- var paramNames = pathParams.Select(p => p.Name);
- if (requiredPathParams != null)
- requiredPathParams.IntersectWith(paramNames);
- else
- requiredPathParams = new HashSet(paramNames);
+ parts.SortBy(p => httpPath.IndexOf($"{{{p.Name}}}", StringComparison.Ordinal));
- allPathParams.AddRange(pathParams);
+ var urlPath = new UrlPath(httpPath, parts, GetDeprecation(operation), operation.XVersionAdded());
+ (urlPath.Deprecation == null ? canonicalPaths : deprecatedPaths).TryAdd(partNames, urlPath);
+
+ if (overloadedParts.Count > 0)
+ overloads.Add((urlPath, overloadedParts));
+
+ if (requiredPathParts != null)
+ requiredPathParts.IntersectWith(partNames);
+ else
+ requiredPathParts = partNames;
}
- urlInfo.OriginalParts = allPathParams.DistinctBy(p => p.Name)
- .Select(p => new UrlPart
- {
- ClrTypeNameOverride = null,
- Deprecated = p.IsDeprecated,
- Description = p.Description,
- Name = p.Name,
- Required = requiredPathParams?.Contains(p.Name) ?? false,
- Type = GetOpenSearchType(p.Schema),
- Options = GetEnumOptions(p.Schema)
- })
- .ToImmutableSortedDictionary(p => p.Name, p => p);
-
- urlInfo.Params = variants.SelectMany(v => v.Path.Parameters.Concat(v.Operation.Parameters))
- .Where(p => p.Kind == OpenApiParameterKind.Query)
- .DistinctBy(p => p.Name)
- .ToImmutableSortedDictionary(p => p.Name, BuildQueryParam);
+ foreach (var (path, renames) in overloads)
+ {
+ foreach (var (from, to) in renames)
+ {
+ var newPath = path.Path.Replace($"{{{from}}}", $"{{{to}}}");
+ var newParts = path.Parts.Select(p => p.Name == from ? allParts[to] : p).ToList();
+ var newPartNames = newParts.Select(p => p.Name).ToHashSet();
+ var newUrlPath = new UrlPath(newPath, newParts, path.Deprecation, path.VersionAdded);
+ (newUrlPath.Deprecation == null ? canonicalPaths : deprecatedPaths).TryAdd(newPartNames, newUrlPath);
+ }
+ }
+
+ //some deprecated paths describe aliases to the canonical using the same path e.g
+ // PUT /{index}/_mapping/{type}
+ // PUT /{index}/{type}/_mappings
+ //
+ //The following routine dedups these occasions and prefers either the canonical path
+ //or the first duplicate deprecated path
+
+ var paths = canonicalPaths.Values
+ .Concat(deprecatedPaths
+ .Where(p => !canonicalPaths.ContainsKey(p.Key))
+ .Select(p => p.Value))
+ .ToList();
+ paths.Sort((p1, p2) => p1.Parts
+ .Zip(p2.Parts)
+ .Select(t => string.Compare(t.First.Name, t.Second.Name, StringComparison.Ordinal))
+ .SkipWhile(c => c == 0)
+ .FirstOrDefault());
+
+ // // now, check for and prefer deprecated URLs
+ //
+ // var finalPathsWithDeprecations = new List(_pathsWithDeprecation.Count);
+ //
+ // foreach (var path in _pathsWithDeprecation)
+ // {
+ // if (path.Deprecation is null &&
+ // DeprecatedPaths.SingleOrDefault(p => p.Path.Equals(path.Path, StringComparison.OrdinalIgnoreCase)) is { } match)
+ // {
+ // finalPathsWithDeprecations.Add(new UrlPath(match, OriginalParts, Paths));
+ // }
+ // else
+ // {
+ // finalPathsWithDeprecations.Add(path);
+ // }
+ // }
+
+ foreach (var partName in requiredPathParts ?? Enumerable.Empty()) allParts[partName].Required = true;
var endpoint = new ApiEndpoint
{
@@ -120,7 +163,14 @@ public static ApiEndpoint From(string name, List<(string HttpPath, OpenApiPathIt
Description = variants[0].Operation.Description,
Url = variants[0].Operation.ExternalDocumentation?.Url
},
- Url = urlInfo,
+ Url = new UrlInformation
+ {
+ AllPaths = paths,
+ Params = variants.SelectMany(v => v.Path.Parameters.Concat(v.Operation.Parameters))
+ .Where(p => p.Kind == OpenApiParameterKind.Query)
+ .DistinctBy(p => p.Name)
+ .ToImmutableSortedDictionary(p => p.Name, BuildQueryParam)
+ },
Body = variants
.Select(v => v.Operation.RequestBody)
.FirstOrDefault(b => b != null) is { } reqBody
@@ -192,11 +242,11 @@ private static IEnumerable GetEnumOptions(JsonSchema schema) =>
?? schema.ActualSchema.Enumeration?.Select(e => e.ToString())
?? Enumerable.Empty();
- private static QueryParameterDeprecation GetDeprecation(IJsonExtensionObject schema) =>
+ private static Deprecation GetDeprecation(IJsonExtensionObject schema) =>
(schema.XDeprecationMessage(), schema.XVersionDeprecated()) switch
{
(null, null) => null,
- var (m, v) => new QueryParameterDeprecation { Description = m, Version = v }
+ var (m, v) => new Deprecation { Description = m, Version = v }
};
private static string GetDescription(OpenApiRequestBody requestBody)
@@ -215,8 +265,15 @@ private static string XDeprecationMessage(this IJsonExtensionObject schema) =>
private static string XVersionDeprecated(this IJsonExtensionObject schema) =>
schema.GetExtension("x-version-deprecated") as string;
- private static string XVersionAdded(this IJsonExtensionObject schema) =>
- schema.GetExtension("x-version-added") as string;
+ private static Version XVersionAdded(this IJsonExtensionObject schema) =>
+ schema.GetExtension("x-version-added") is string s
+ ? s.Split('.').Length switch
+ {
+ 1 => new Version($"{s}.0.0"),
+ 2 => new Version($"{s}.0"),
+ _ => new Version(s),
+ }
+ : null;
private static string XDataType(this IJsonExtensionObject schema) =>
schema.GetExtension("x-data-type") as string;
diff --git a/src/ApiGenerator/Generator/CodeGenerator.cs b/src/ApiGenerator/Generator/CodeGenerator.cs
index 0f9b35e627..9a0a5cb025 100644
--- a/src/ApiGenerator/Generator/CodeGenerator.cs
+++ b/src/ApiGenerator/Generator/CodeGenerator.cs
@@ -30,6 +30,7 @@
using System.Collections.Generic;
using System.Linq;
using ApiGenerator.Domain.Code.HighLevel.Requests;
+using Version = SemanticVersioning.Version;
namespace ApiGenerator.Generator
{
@@ -45,11 +46,11 @@ public static string CatFormatPropertyGenerator(string type, string name, string
public static string PropertyGenerator(string type, string name, string key, string setter) =>
$"public {type} {name} {{ get => Q<{type}>(\"{key}\"); set => Q(\"{key}\", {setter}); }}";
- public static string Property(string @namespace, string type, string name, string key, string setter, string obsolete, string versionAdded, params string[] doc)
+ public static string Property(string @namespace, string type, string name, string key, string setter, string obsolete, Version versionAdded, params string[] doc)
{
var components = new List();
foreach (var d in RenderDocumentation(doc)) A(d);
- if (!string.IsNullOrWhiteSpace(versionAdded)) A($"///Supported by OpenSearch servers of version {versionAdded} or greater.");
+ if (versionAdded != null) A($"/// Supported by OpenSearch servers of version {versionAdded} or greater.");
if (!string.IsNullOrWhiteSpace(obsolete)) A($"[Obsolete(\"{obsolete}\")]");
var generated = @namespace != null && @namespace == "Cat" && name == "Format"
@@ -89,15 +90,15 @@ private static IEnumerable RenderDocumentation(params string[] doc)
{
case 0: yield break;
case 1:
- yield return $"///{doc[0]}";
+ yield return $"/// {doc[0]}";
yield break;
default:
- yield return "///";
+ yield return "/// ";
foreach (var d in doc) yield return $"/// {d}";
- yield return "///";
+ yield return "/// ";
yield break;
}
diff --git a/src/ApiGenerator/Views/HighLevel/Client/FluentSyntax/FluentMethod.cshtml b/src/ApiGenerator/Views/HighLevel/Client/FluentSyntax/FluentMethod.cshtml
index 10b88e61eb..e748bf9fff 100644
--- a/src/ApiGenerator/Views/HighLevel/Client/FluentSyntax/FluentMethod.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Client/FluentSyntax/FluentMethod.cshtml
@@ -3,10 +3,10 @@
@inherits ApiGenerator.CodeTemplatePage
@{
var method = !Model.Async ? Model.Syntax.MethodName : string.Format("{0}Async", Model.Syntax.MethodName);
- var asyncKeyword = Model.Syntax.InterfaceResponse && Model.Async ? "async " : String.Empty;
+ var asyncKeyword = Model.Syntax.InterfaceResponse && Model.Async ? "async " : string.Empty;
var awaitKeyWord = Model.Syntax.InterfaceResponse && Model.Async ? "await ": string.Empty;
- var configureAwait = Model.Syntax.InterfaceResponse && Model.Async ? ".ConfigureAwait(false)" : String.Empty;
-
+ var configureAwait = Model.Syntax.InterfaceResponse && Model.Async ? ".ConfigureAwait(false)" : string.Empty;
+
var requestMethodGenerics = Model.Syntax.RequestMethodGenerics;
var descriptor = Model.Syntax.DescriptorName;
var selectorArgs = Model.Syntax.SelectorArguments();
diff --git a/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.Namespace.cshtml b/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.Namespace.cshtml
index 331099fb9b..c3c8e5d31b 100644
--- a/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.Namespace.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.Namespace.cshtml
@@ -18,12 +18,12 @@ using OpenSearch.Net.@(CsharpNames.ApiNamespace).@ns@(CsharpNames.ApiNamespaceSu
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace OpenSearch.Client.@(CsharpNames.ApiNamespace).@ns@(CsharpNames.ApiNamespaceSuffix)
{
- ///
+ ///
/// @ns.SplitPascalCase() APIs.
/// Not intended to be instantiated directly. Use the property
/// on .
- ///
- ///
+ ///
+ ///
public partial class @(CsharpNames.HighLevelClientNamespacePrefix)@ns@(CsharpNames.ClientNamespaceSuffix) : NamespacedClientProxy
{
internal @(CsharpNames.HighLevelClientNamespacePrefix)@ns@(CsharpNames.ClientNamespaceSuffix)(OpenSearchClient client) : base(client) {}
diff --git a/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.cshtml b/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.cshtml
index 9ee1e2cd75..c57e3e1dfe 100644
--- a/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Client/Implementation/OpenSearchClient.cshtml
@@ -1,6 +1,6 @@
@using System.Linq
@using ApiGenerator.Domain
-@using ApiGenerator
+@using ApiGenerator
@using ApiGenerator.Domain.Code
@inherits CodeTemplatePage
@{ await IncludeGeneratorNotice(); }
@@ -17,15 +17,15 @@ using OpenSearch.Client;
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace OpenSearch.Client
{
- ///
- ///OpenSearch high level client
- ///
+ ///
+ /// OpenSearch high level client
+ ///
public partial class OpenSearchClient : IOpenSearchClient
{
foreach (var ns in namespaces)
{
- ///@(ns.SplitPascalCase()) APIs
+ /// @(ns.SplitPascalCase()) APIs
public @CsharpNames.HighLevelClientNamespacePrefix@(ns)@CsharpNames.ClientNamespaceSuffix @ns { get; private set; }
}
@@ -41,7 +41,7 @@ namespace OpenSearch.Client
}
-
+
foreach (var kv in Model.EndpointsPerNamespaceHighLevel)
{
diff --git a/src/ApiGenerator/Views/HighLevel/Client/Interface/IOpenSearchClient.cshtml b/src/ApiGenerator/Views/HighLevel/Client/Interface/IOpenSearchClient.cshtml
index 2cef1f859e..3dd2c0ba9d 100644
--- a/src/ApiGenerator/Views/HighLevel/Client/Interface/IOpenSearchClient.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Client/Interface/IOpenSearchClient.cshtml
@@ -15,16 +15,16 @@ using OpenSearch.Client;
namespace OpenSearch.Client
{
- ///
- ///OpenSearch high level client
- ///
- public partial interface IOpenSearchClient
+ ///
+ /// OpenSearch high level client
+ ///
+ public partial interface IOpenSearchClient
{
@foreach(var (ns, endpoints) in Model.EndpointsPerNamespaceHighLevel)
{
if (ns != CsharpNames.RootNamespace)
{
- ///@ns.SplitPascalCase() APIs
+ /// @ns.SplitPascalCase() APIs
@CsharpNames.HighLevelClientNamespacePrefix@(ns)@CsharpNames.ClientNamespaceSuffix @ns { get; }
continue;
diff --git a/src/ApiGenerator/Views/HighLevel/Client/MethodXmlDocs.cshtml b/src/ApiGenerator/Views/HighLevel/Client/MethodXmlDocs.cshtml
index 26445d9ea9..0a4ec9a61b 100644
--- a/src/ApiGenerator/Views/HighLevel/Client/MethodXmlDocs.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Client/MethodXmlDocs.cshtml
@@ -1,8 +1,18 @@
@using ApiGenerator
@using ApiGenerator.Domain.Code.HighLevel.Methods;
+@using Version = SemanticVersioning.Version;
@inherits CodeTemplatePage
///
/// @Raw(Model.XmlDocSummary)
/// @Raw("")
/// @Model.DocumentationLink
///
+@if (Model.VersionAdded is {} versionAdded && versionAdded > new Version("1.0.0"))
+{
+/// Supported by OpenSearch servers of version @(versionAdded) or greater.
+
+}
+@if (Model.Deprecated is {} deprecation)
+{
+@Raw($"[Obsolete(\"{deprecation}\")]")
+}
diff --git a/src/ApiGenerator/Views/HighLevel/Descriptors/Descriptor.cshtml b/src/ApiGenerator/Views/HighLevel/Descriptors/Descriptor.cshtml
index f2ca53d42f..2e0626c3c1 100644
--- a/src/ApiGenerator/Views/HighLevel/Descriptors/Descriptor.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Descriptors/Descriptor.cshtml
@@ -10,9 +10,9 @@
var baseInterface = names.GenericOrNonGenericInterfacePreference;
var apiLookup = $"ApiUrlsLookups.{Model.CsharpNames.Namespace}{Model.CsharpNames.MethodName}";
}
- ///Descriptor for @names.MethodName@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
+ /// Descriptor for @names.MethodName@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
public partial class @Raw(type) @(Raw(string.Format(" : RequestDescriptorBase<{0},{1}, {2}>, {2}", type,names.ParametersName, concreteInterface)))
- {
+ {
internal override ApiUrls ApiUrls => @apiLookup;
@foreach (var c in Model.Constructors)
{
@@ -50,36 +50,27 @@
var tSuffix = (t == "bool" || t == "bool?") ? " = true" : "";
var typed = !string.IsNullOrEmpty(names.GenericsDeclaredOnDescriptor);
var g = typed ? names.GenericsDeclaredOnDescriptor.Replace("<", "").Replace(">", "") : "T";
- var desc = param.DescriptionHighLevel.ToList();
-
- await IncludeAsync("HighLevel/Descriptors/XmlDocs.cshtml", desc);
- if (!string.IsNullOrWhiteSpace(param.VersionAdded))
- {
-
- ///Supported by OpenSearch servers of version @(param.VersionAdded) or greater.
- }
+ await IncludeAsync("HighLevel/Descriptors/XmlDocs.cshtml", param);
if(!string.IsNullOrWhiteSpace(param.Obsolete))
{
-
- [Obsolete("@Raw(param.Obsolete)")]
-
+ [Obsolete("@Raw(param.Obsolete)")]
+
}
-
- public @Raw(type) @(param.ClsName)(@param.DescriptorArgumentType @param.ClsArgumentName@tSuffix) => Qs("@original", @(param.ClsArgumentName));
+ public @Raw(type) @(param.ClsName)(@param.DescriptorArgumentType @param.ClsArgumentName@tSuffix) => Qs("@original", @(param.ClsArgumentName));
if (param.IsFieldsParam)
{
- ///@param.Description
+ /// @param.Description
public @Raw(type) @param.ClsName@(Raw(typed ? "" : ""))(params @Raw("Expression>[]") fields) @Raw(typed ? "" : "where " + g + " : class") => Qs("@original", fields?@Raw(".Select(e=>(Field)e)"));
}
else if (param.IsFieldParam)
{
- ///@param.Description
+ /// @param.Description
public @Raw(type) @param.ClsName@(Raw(typed ? "" : ""))(@Raw("Expression>") field) @Raw(typed ? "" : "where " + g + " : class") => Qs("@original", (Field)field);
}
@@ -90,6 +81,6 @@
public bool IsUnmapped => true;
public bool UseIsUnmapped => IsUnmapped;
- }
+ }
}
diff --git a/src/ApiGenerator/Views/HighLevel/Descriptors/XmlDocs.cshtml b/src/ApiGenerator/Views/HighLevel/Descriptors/XmlDocs.cshtml
index 5015387ffa..5435af2bf5 100644
--- a/src/ApiGenerator/Views/HighLevel/Descriptors/XmlDocs.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Descriptors/XmlDocs.cshtml
@@ -1,16 +1,24 @@
@using System.Linq
-@inherits ApiGenerator.CodeTemplatePage>
+@using Version = SemanticVersioning.Version
+@inherits ApiGenerator.CodeTemplatePage
@{
- var description = Model.Count == 1 ? Model.First() : string.Join($"{Environment.NewLine}\t\t", Model.Select(d => "/// " + d));
- if (Model.Count == 1)
+ var docs = Model.DescriptionHighLevel.ToList();
+ var description = docs.Count == 1 ? docs.First() : string.Join($"{Environment.NewLine}\t\t", docs.Select(d => "/// " + d));
+ if (docs.Count == 1)
{
- ///@Raw(description)
+ /// @Raw(description)
+
}
else
{
- ///
+ ///
@Raw(description)
- ///
+ ///
}
+ if (Model.VersionAdded is {} versionAdded && versionAdded > new Version("1.0.0"))
+ {
+ /// Supported by OpenSearch servers of version @(versionAdded) or greater.
+
+ }
}
diff --git a/src/ApiGenerator/Views/HighLevel/Requests/ApiUrlsLookup.cshtml b/src/ApiGenerator/Views/HighLevel/Requests/ApiUrlsLookup.cshtml
index 68d92443e6..4cebf146e9 100644
--- a/src/ApiGenerator/Views/HighLevel/Requests/ApiUrlsLookup.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Requests/ApiUrlsLookup.cshtml
@@ -15,7 +15,7 @@ namespace OpenSearch.Client
continue;
}
var propertyName = $"{endpoint.CsharpNames.Namespace}{endpoint.CsharpNames.MethodName}";
- var paths = endpoint.Url.Paths.Count == 0 ? endpoint.Url.PathsWithDeprecations : endpoint.Url.Paths;
+ var paths = !endpoint.Url.Paths.Any() ? endpoint.Url.AllPaths : endpoint.Url.Paths;
internal static readonly ApiUrls @(Raw(propertyName)) = new(new [] {@Raw(string.Join(", ", paths.Select(p=>$"\"{p.Path.TrimStart('/')}\"")))});
diff --git a/src/ApiGenerator/Views/HighLevel/Requests/RequestImplementations.cshtml b/src/ApiGenerator/Views/HighLevel/Requests/RequestImplementations.cshtml
index b438e2feff..0be9404b61 100644
--- a/src/ApiGenerator/Views/HighLevel/Requests/RequestImplementations.cshtml
+++ b/src/ApiGenerator/Views/HighLevel/Requests/RequestImplementations.cshtml
@@ -7,7 +7,7 @@
@{
var apiLookup = $"ApiUrlsLookups.{Model.CsharpNames.Namespace}{Model.CsharpNames.MethodName}";
}
-///Request for @Model.CsharpNames.MethodName@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
+/// Request for @Model.CsharpNames.MethodName@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
@if (Model.Stability != Stability.Stable)
{
string warningMessage = "";
@@ -20,8 +20,8 @@
warningMessage = "this functionality is in beta and is subject to change. The design and code is less mature than official GA features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA features.";
break;
}
-
-///@Raw("Note: " + Model.Stability + " within the OpenSearch server, " + warningMessage + "")
+
+/// @Raw("Note: " + Model.Stability + " within the OpenSearch server, " + warningMessage + "")
}
public partial class @Raw(Model.Name) @Raw(string.Format(": PlainRequestBase<{0}>, {1}", Model.CsharpNames.ParametersName, Model.InterfaceName))
diff --git a/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.Namespace.cshtml b/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.Namespace.cshtml
index 87a06d99a4..7711359b87 100644
--- a/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.Namespace.cshtml
+++ b/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.Namespace.cshtml
@@ -1,6 +1,6 @@
@using System.Collections.ObjectModel
@using System.Linq
-@using ApiGenerator
+@using ApiGenerator
@using ApiGenerator.Domain.Code
@using ApiGenerator.Domain.Specification
@inherits CodeTemplatePage>>
@@ -25,20 +25,20 @@ using static OpenSearch.Net.HttpMethod;
// ReSharper disable RedundantExtendsListEntry
namespace OpenSearch.Net.@(CsharpNames.ApiNamespace).@ns@(CsharpNames.ApiNamespaceSuffix)
{
- ///
+ ///
/// @ns.SplitPascalCase() APIs.
/// Not intended to be instantiated directly. Use the property
/// on .
- ///
- ///
+ ///
+ ///
public partial class @(CsharpNames.LowLevelClientNamespacePrefix)@ns@(CsharpNames.ClientNamespaceSuffix) : NamespacedClientProxy
{
internal @(CsharpNames.LowLevelClientNamespacePrefix)@ns@(CsharpNames.ClientNamespaceSuffix)(OpenSearchLowLevelClient client) : base(client) {}
@if (ns == "Cat")
{
- protected override string ContentType { get; } = "text/plain";
+ protected override string ContentType => "text/plain";
}
- @{
+ @{
var methods = endpoints.SelectMany(e=>e.LowLevelClientMethods).ToList();
foreach (var method in methods)
{
diff --git a/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.cshtml b/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.cshtml
index 231413f7a1..2795157ec4 100644
--- a/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.cshtml
+++ b/src/ApiGenerator/Views/LowLevel/Client/Implementation/OpenSearchLowLevelClient.cshtml
@@ -1,6 +1,6 @@
@using System.Linq
@using ApiGenerator.Domain
-@using ApiGenerator
+@using ApiGenerator
@using ApiGenerator.Domain.Code
@inherits CodeTemplatePage
@{ await IncludeGeneratorNotice(); }
@@ -23,15 +23,15 @@ using static OpenSearch.Net.HttpMethod;
// ReSharper disable RedundantExtendsListEntry
namespace OpenSearch.Net
{
- ///
- ///OpenSearch low level client
- ///
+ ///
+ /// OpenSearch low level client
+ ///
public partial class OpenSearchLowLevelClient : IOpenSearchLowLevelClient
{
foreach (var ns in namespaces)
{
- public @(CsharpNames.LowLevelClientNamespacePrefix)@(ns)@(CsharpNames.ClientNamespaceSuffix) @ns { get; private set; }
+ public @(CsharpNames.LowLevelClientNamespacePrefix)@(ns)@(CsharpNames.ClientNamespaceSuffix) @ns { get; private set; }
}
@@ -46,7 +46,7 @@ namespace OpenSearch.Net
}
-
+
foreach (var (ns, endpoints) in Model.EndpointsPerNamespaceLowLevel)
{
diff --git a/src/ApiGenerator/Views/LowLevel/Client/Interface/IOpenSearchLowLevelClient.cshtml b/src/ApiGenerator/Views/LowLevel/Client/Interface/IOpenSearchLowLevelClient.cshtml
index c18cf883b8..4a90af2fb8 100644
--- a/src/ApiGenerator/Views/LowLevel/Client/Interface/IOpenSearchLowLevelClient.cshtml
+++ b/src/ApiGenerator/Views/LowLevel/Client/Interface/IOpenSearchLowLevelClient.cshtml
@@ -17,17 +17,17 @@ using OpenSearch.Net;
namespace OpenSearch.Net
{
- ///
- ///OpenSearch low level client
- ///
- public partial interface IOpenSearchLowLevelClient
+ ///
+ /// OpenSearch low level client
+ ///
+ public partial interface IOpenSearchLowLevelClient
{
@foreach(var (ns, endpoints) in Model.EndpointsPerNamespaceLowLevel)
{
if (ns != CsharpNames.RootNamespace)
{
- ///@ns.SplitPascalCase() APIs
+ /// @ns.SplitPascalCase() APIs
@CsharpNames.LowLevelClientNamespacePrefix@(ns)@CsharpNames.ClientNamespaceSuffix @ns { get; }
continue;
diff --git a/src/ApiGenerator/Views/LowLevel/Client/Methods/MethodDocs.cshtml b/src/ApiGenerator/Views/LowLevel/Client/Methods/MethodDocs.cshtml
index 46423d412d..2801001566 100644
--- a/src/ApiGenerator/Views/LowLevel/Client/Methods/MethodDocs.cshtml
+++ b/src/ApiGenerator/Views/LowLevel/Client/Methods/MethodDocs.cshtml
@@ -1,14 +1,16 @@
@using ApiGenerator
@using ApiGenerator.Domain.Code.LowLevel
@using ApiGenerator.Domain.Specification
+@using SemanticVersioning
+@using Version = SemanticVersioning.Version
@inherits ApiGenerator.CodeTemplatePage
-///@Model.HttpMethod on @Model.Path@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
+/// @Model.HttpMethod on @Model.Path@(Raw(Model.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + Model.OfficialDocumentationLink + ""))
@foreach (var part in Model.Parts)
{
- ///@Raw("")@part.Description@Raw("")
+ /// @Raw("")@part.Description@Raw("")
}
- ///@Raw(@"Request specific configuration such as querystring parameters & request specific connection settings.")
+ /// @Raw(@"Request specific configuration such as querystring parameters & request specific connection settings.")
@if (Model.Stability != Stability.Stable)
{
string warningMessage = "";
@@ -23,11 +25,15 @@
}
warningMessage += " This functionality is subject to potential breaking changes within a minor version, meaning that your referencing code may break when this library is upgraded.";
-
- ///@Raw("Note: " + Model.Stability + " within the OpenSearch server, " + warningMessage + "")
+ /// @Raw("Note: " + Model.Stability + " within the OpenSearch server, " + warningMessage + "")
+
+}
+ @if (Model.VersionAdded is {} versionAdded && versionAdded > new Version("1.0.0"))
+ {
+ /// @Raw("Supported by OpenSearch servers of version " + versionAdded + " or greater.")
}
- @if (Model.DeprecatedPath != null)
+ @if (Model.Deprecation is {} deprecation)
{
- [Obsolete("Deprecated in version @Model.DeprecatedPath.Version: @Raw(Model.DeprecatedPath.Description)")]
+ [Obsolete("Deprecated in version @deprecation.Version: @Raw(deprecation.Description)")]
}
diff --git a/src/ApiGenerator/Views/LowLevel/RequestParameters/RequestParameters.cshtml b/src/ApiGenerator/Views/LowLevel/RequestParameters/RequestParameters.cshtml
index 0295c09fd4..fd477d54ef 100644
--- a/src/ApiGenerator/Views/LowLevel/RequestParameters/RequestParameters.cshtml
+++ b/src/ApiGenerator/Views/LowLevel/RequestParameters/RequestParameters.cshtml
@@ -25,8 +25,8 @@ namespace OpenSearch.Net@(ns)
var supportsBody = endpoint.Body != null;
var names = r.CsharpNames;
- ///Request options for @names.MethodName@Raw(r.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + r.OfficialDocumentationLink + "")
- public partial class @names.ParametersName : RequestParameters<@names.ParametersName>
+ /// Request options for @names.MethodName@Raw(r.OfficialDocumentationLink.IsNullOrEmpty() ? "" : " " + r.OfficialDocumentationLink + "")
+ public partial class @names.ParametersName : RequestParameters<@names.ParametersName>
{
public override HttpMethod DefaultHttpMethod => HttpMethod.@r.HttpMethod;
public override bool SupportsBody => @(supportsBody ? "true" : "false");