Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/index parameter description #3071

Merged
merged 3 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added support for indexer parameter description. [#2978](https://github.com/microsoft/kiota/issues/2978)

### Changed

## [1.5.0] - 2023-08-04
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/CodeDOM/CodeClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void AddIndexer(params CodeIndexer[] indexers)
foreach (var value in indexers)
{
var existingIndexers = InnerChildElements.Values.OfType<CodeIndexer>().ToArray();
if (Array.Exists(existingIndexers, x => !x.IndexParameterName.Equals(value.IndexParameterName, StringComparison.OrdinalIgnoreCase)) ||
if (Array.Exists(existingIndexers, x => !x.IndexParameter.Name.Equals(value.IndexParameter.Name, StringComparison.OrdinalIgnoreCase)) ||
InnerChildElements.Values.OfType<CodeMethod>().Any(static x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility)))
{
foreach (var existingIndexer in existingIndexers)
Expand Down
37 changes: 15 additions & 22 deletions src/Kiota.Builder/CodeDOM/CodeIndexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,6 @@
namespace Kiota.Builder.CodeDOM;
public class CodeIndexer : CodeTerminal, IDocumentedElement, IDeprecableElement, ICloneable
{
#nullable disable // exposing property is required
private CodeTypeBase indexType;
#nullable enable
public required CodeTypeBase IndexType
{
get => indexType; set
{
ArgumentNullException.ThrowIfNull(value);
EnsureElementsAreChildren(value);
indexType = value;
}
}
#nullable disable // exposing property is required
private CodeTypeBase returnType;
#nullable enable
Expand All @@ -27,14 +15,21 @@ public required CodeTypeBase ReturnType
returnType = value;
}
}
#nullable disable // exposing property is required
private CodeParameter indexParameter;
#nullable enable
/// <summary>
/// The name of the parameter to use for the indexer.
/// The parameter to use for the indexer.
/// </summary>
public required string IndexParameterName
public required CodeParameter IndexParameter
{
get; set;
get => indexParameter; set
{
ArgumentNullException.ThrowIfNull(value);
EnsureElementsAreChildren(value);
indexParameter = value;
}
}
public string SerializationName { get; set; } = string.Empty;
public CodeDocumentation Documentation { get; set; } = new();
/// <summary>
/// The Path segment to use for the method name when using back-compatible methods.
Expand All @@ -50,13 +45,11 @@ public object Clone()
{
Name = Name,
Parent = Parent,
IndexType = IndexType.Clone() as CodeTypeBase ?? throw new InvalidOperationException($"Cloning failed. Cloned type is invalid."),
ReturnType = ReturnType.Clone() as CodeTypeBase ?? throw new InvalidOperationException($"Cloning failed. Cloned type is invalid."),
IndexParameterName = IndexParameterName,
SerializationName = SerializationName,
Documentation = Documentation.Clone() as CodeDocumentation ?? throw new InvalidOperationException($"Cloning failed. Cloned type is invalid."),
ReturnType = (CodeTypeBase)ReturnType.Clone(),
Documentation = (CodeDocumentation)Documentation.Clone(),
PathSegment = PathSegment,
Deprecation = Deprecation == null ? null : Deprecation with { }
Deprecation = Deprecation == null ? null : Deprecation with { },
IndexParameter = (CodeParameter)IndexParameter.Clone(),
};
}
}
18 changes: 6 additions & 12 deletions src/Kiota.Builder/CodeDOM/CodeMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,8 @@ public static CodeMethod FromIndexer(CodeIndexer originalIndexer, Func<string, s
IsStatic = false,
Access = AccessModifier.Public,
Kind = CodeMethodKind.IndexerBackwardCompatibility,
Name = methodNameCallback(originalIndexer.IndexParameterName) + (typeSpecificOverload ? originalIndexer.IndexType.Name.ToFirstCharacterUpperCase() : string.Empty),
Documentation = new()
{
Description = originalIndexer.Documentation.Description,
},
Name = methodNameCallback(originalIndexer.IndexParameter.Name) + (typeSpecificOverload ? originalIndexer.IndexParameter.Type.Name.ToFirstCharacterUpperCase() : string.Empty),
Documentation = (CodeDocumentation)originalIndexer.Documentation.Clone(),
ReturnType = (CodeTypeBase)originalIndexer.ReturnType.Clone(),
OriginalIndexer = originalIndexer,
Deprecation = originalIndexer.Deprecation,
Expand All @@ -103,15 +100,12 @@ public static CodeMethod FromIndexer(CodeIndexer originalIndexer, Func<string, s
method.ReturnType.IsNullable = false;
var parameter = new CodeParameter
{
Name = parameterNameCallback(originalIndexer.IndexParameterName),
Name = parameterNameCallback(originalIndexer.IndexParameter.Name),
Optional = false,
Kind = ParameterKindForConvertedIndexers,
Documentation = new()
{
Description = "Unique identifier of the item",
},
Type = originalIndexer.IndexType?.Clone() is CodeTypeBase indexType ? indexType : throw new InvalidOperationException("index type is null"),
SerializationName = originalIndexer.SerializationName,
Documentation = (CodeDocumentation)originalIndexer.IndexParameter.Documentation.Clone(),
Type = (CodeTypeBase)originalIndexer.IndexParameter.Type.Clone(),
SerializationName = originalIndexer.IndexParameter.SerializationName,
};
parameter.Type.IsNullable = parameterNullable;
method.AddParameter(parameter);
Expand Down
24 changes: 16 additions & 8 deletions src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@
};
}
private static CodeType DefaultIndexerParameterType => new() { Name = "string", IsExternal = true };
private CodeType GetIndexerParameterType(OpenApiUrlTreeNode currentNode, OpenApiUrlTreeNode parentNode)
private CodeParameter GetIndexerParameterType(OpenApiUrlTreeNode currentNode, OpenApiUrlTreeNode parentNode)
{
var parameterName = currentNode.Path[parentNode.Path.Length..].Trim('\\', ForwardSlash, '{', '}');
var parameter = currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem) ? pathItem.Parameters
Expand All @@ -987,9 +987,19 @@
_ => GetPrimitiveType(parameter.Schema),
} ?? DefaultIndexerParameterType;
type.IsNullable = false;
return type;
var result = new CodeParameter
{
Type = type,
SerializationName = currentNode.Segment.SanitizeParameterNameForUrlTemplate(),
Name = currentNode.Segment.CleanupSymbolName(),
Documentation = new()
{
Description = parameter?.Description.CleanupDescription() is string description && !string.IsNullOrEmpty(description) ? description : "Unique identifier of the item",
},
};
return result;
}
private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, CodeType parameterType, OpenApiUrlTreeNode currentNode, OpenApiUrlTreeNode parentNode)
private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, CodeParameter parameter, OpenApiUrlTreeNode currentNode, OpenApiUrlTreeNode parentNode)
{
logger.LogTrace("Creating indexer {Name}", childIdentifier);
var result = new List<CodeIndexer> { new CodeIndexer
Expand All @@ -999,20 +1009,18 @@
{
Description = currentNode.GetPathItemDescription(Constants.DefaultOpenApiLabel, $"Gets an item from the {currentNode.GetNodeNamespaceFromPath(config.ClientNamespaceName)} collection"),
},
IndexType = parameterType,
ReturnType = new CodeType { Name = childType },
SerializationName = currentNode.Segment.SanitizeParameterNameForUrlTemplate(),
PathSegment = parentNode.GetNodeNamespaceFromPath(string.Empty).Split('.').Last(),
IndexParameterName = currentNode.Segment.CleanupSymbolName(),
Deprecation = currentNode.GetDeprecationInformation(),
IndexParameter = parameter,
}};

if (!"string".Equals(parameterType.Name, StringComparison.OrdinalIgnoreCase))
if (!"string".Equals(parameter.Type.Name, StringComparison.OrdinalIgnoreCase))
{ // adding a second indexer for the string version of the parameter so we keep backward compatibility
//TODO remove for v2

Check warning on line 1020 in src/Kiota.Builder/KiotaBuilder.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment.
var backCompatibleValue = (CodeIndexer)result[0].Clone();
backCompatibleValue.Name += "-string";
backCompatibleValue.IndexType = DefaultIndexerParameterType;
backCompatibleValue.IndexParameter.Type = DefaultIndexerParameterType;
backCompatibleValue.Deprecation = new DeprecationInformation("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.");
result.Add(backCompatibleValue);
}
Expand Down Expand Up @@ -1631,7 +1639,7 @@
{
Name = declarationName,//TODO set the flag property
Documentation = new()
{

Check warning on line 1642 in src/Kiota.Builder/KiotaBuilder.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment.
Description = !string.IsNullOrEmpty(schemaDescription) || !string.IsNullOrEmpty(schema.Reference?.Id) ?
schemaDescription : // if it's a referenced component, we shouldn't use the path item description as it makes it indeterministic
currentNode.GetPathItemDescription(Constants.DefaultOpenApiLabel),
Expand Down
14 changes: 7 additions & 7 deletions src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -690,27 +690,27 @@
CrawlTree(currentElement, MoveClassesWithNamespaceNamesUnderNamespace);
}
private static readonly Func<string, CodeIndexer, bool> IsIndexerTypeSpecificVersion =
(currentIndexerParameterName, existingIndexer) => currentIndexerParameterName.Equals(existingIndexer.IndexParameterName, StringComparison.OrdinalIgnoreCase) && !"string".Equals(existingIndexer.IndexType.Name, StringComparison.OrdinalIgnoreCase);
(currentIndexerParameterName, existingIndexer) => currentIndexerParameterName.Equals(existingIndexer.IndexParameter.Name, StringComparison.OrdinalIgnoreCase) && !"string".Equals(existingIndexer.IndexParameter.Type.Name, StringComparison.OrdinalIgnoreCase);
protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentElement, bool parameterNullable, Func<string, string> methodNameCallback, Func<string, string> parameterNameCallback, GenerationLanguage language)
{
if (currentElement is CodeIndexer currentIndexer &&
currentElement.Parent is CodeClass indexerParentClass)
{
if (indexerParentClass.ContainsMember(currentElement.Name)) // TODO remove condition for v2 necessary because of the second case of Go block

Check warning on line 699 in src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment.
indexerParentClass.RemoveChildElement(currentElement);
//TODO remove who block except for last else if body for v2

Check warning on line 701 in src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs

View workflow job for this annotation

GitHub Actions / Build

Complete the task associated to this 'TODO' comment.
var isIndexerStringBackwardCompatible = "string".Equals(currentIndexer.IndexType.Name, StringComparison.OrdinalIgnoreCase) &&
var isIndexerStringBackwardCompatible = "string".Equals(currentIndexer.IndexParameter.Type.Name, StringComparison.OrdinalIgnoreCase) &&
currentIndexer.Deprecation is not null && currentIndexer.Deprecation.IsDeprecated &&
(indexerParentClass.Methods.Any(x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility) && x.OriginalIndexer is not null && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameterName, x.OriginalIndexer)) ||
(indexerParentClass.Indexer != null && indexerParentClass.Indexer != currentIndexer && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameterName, indexerParentClass.Indexer)));
(indexerParentClass.Methods.Any(x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility) && x.OriginalIndexer is not null && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameter.Name, x.OriginalIndexer)) ||
(indexerParentClass.Indexer != null && indexerParentClass.Indexer != currentIndexer && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameter.Name, indexerParentClass.Indexer)));
if (isIndexerStringBackwardCompatible && language == GenerationLanguage.Go)
{
if (indexerParentClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility) && x.OriginalIndexer is not null && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameterName, x.OriginalIndexer)) is CodeMethod typeSpecificCompatibleMethod &&
if (indexerParentClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.IndexerBackwardCompatibility) && x.OriginalIndexer is not null && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameter.Name, x.OriginalIndexer)) is CodeMethod typeSpecificCompatibleMethod &&
typeSpecificCompatibleMethod.OriginalIndexer is not null)
{
indexerParentClass.RenameChildElement(typeSpecificCompatibleMethod.Name, typeSpecificCompatibleMethod.Name + typeSpecificCompatibleMethod.OriginalIndexer.IndexType.Name.ToFirstCharacterUpperCase());
indexerParentClass.RenameChildElement(typeSpecificCompatibleMethod.Name, typeSpecificCompatibleMethod.Name + typeSpecificCompatibleMethod.OriginalIndexer.IndexParameter.Type.Name.ToFirstCharacterUpperCase());
}
else if (indexerParentClass.Indexer != null && indexerParentClass.Indexer != currentIndexer && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameterName, indexerParentClass.Indexer))
else if (indexerParentClass.Indexer != null && indexerParentClass.Indexer != currentIndexer && IsIndexerTypeSpecificVersion(currentIndexer.IndexParameter.Name, indexerParentClass.Indexer))
{
var specificIndexer = indexerParentClass.Indexer;
indexerParentClass.RemoveChildElement(specificIndexer);
Expand Down
5 changes: 3 additions & 2 deletions src/Kiota.Builder/Writers/CSharp/CodeIndexerWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ public override void WriteCodeElement(CodeIndexer codeElement, LanguageWriter wr
if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class");
var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement);
conventions.WriteShortDescription(codeElement.Documentation.Description, writer);
writer.WriteLine($"{conventions.DocCommentPrefix}<param name=\"position\">{codeElement.IndexParameter.Documentation.Description.CleanupXMLString()}</param>");
conventions.WriteDeprecationAttribute(codeElement, writer);
writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexType, codeElement)} position] {{ get {{");
writer.StartBlock($"public {returnType} this[{conventions.GetTypeString(codeElement.IndexParameter.Type, codeElement)} position] {{ get {{");
if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProp)
conventions.AddParametersAssignment(writer, pathParametersProp.Type, pathParametersProp.Name.ToFirstCharacterUpperCase(), string.Empty, (codeElement.IndexType, codeElement.SerializationName, "position"));
conventions.AddParametersAssignment(writer, pathParametersProp.Type, pathParametersProp.Name.ToFirstCharacterUpperCase(), string.Empty, (codeElement.IndexParameter.Type, codeElement.IndexParameter.SerializationName, "position"));
conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName, "return ");
writer.CloseBlock("} }");
}
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ private void WriteIndexerBody(CodeMethod codeElement, CodeClass parentClass, Lan
{
if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty && codeElement.OriginalIndexer != null)
conventions.AddParametersAssignment(writer, pathParametersProperty.Type, $"this.{pathParametersProperty.Name}",
parameters: (codeElement.OriginalIndexer.IndexType, codeElement.OriginalIndexer.SerializationName, codeElement.OriginalIndexer.IndexParameterName.ToFirstCharacterLowerCase()));
parameters: (codeElement.OriginalIndexer.IndexParameter.Type, codeElement.OriginalIndexer.IndexParameter.SerializationName, codeElement.OriginalIndexer.IndexParameter.Name.ToFirstCharacterLowerCase()));
conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName);
}
private void WriteDeserializerBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer, bool inherits)
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ private void WriteIndexerBody(CodeMethod codeElement, CodeClass parentClass, str
if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty &&
codeElement.OriginalIndexer != null)
conventions.AddParametersAssignment(writer, pathParametersProperty.Type, $"$this->{pathParametersProperty.Name}",
(codeElement.OriginalIndexer.IndexType, codeElement.OriginalIndexer.SerializationName, $"${codeElement.OriginalIndexer.IndexParameterName.ToFirstCharacterLowerCase()}"));
(codeElement.OriginalIndexer.IndexParameter.Type, codeElement.OriginalIndexer.IndexParameter.SerializationName, $"${codeElement.OriginalIndexer.IndexParameter.Name.ToFirstCharacterLowerCase()}"));
conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName, pathParameters);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private void WriteIndexerBody(CodeMethod codeElement, CodeClass parentClass, str
if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty &&
codeElement.OriginalIndexer != null)
conventions.AddParametersAssignment(writer, pathParametersProperty.Type, $"self.{pathParametersProperty.Name}",
(codeElement.OriginalIndexer.IndexType, codeElement.OriginalIndexer.SerializationName, codeElement.OriginalIndexer.IndexParameterName.ToSnakeCase()));
(codeElement.OriginalIndexer.IndexParameter.Type, codeElement.OriginalIndexer.IndexParameter.SerializationName, codeElement.OriginalIndexer.IndexParameter.Name.ToSnakeCase()));
conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName);
}
private void WriteRequestBuilderWithParametersBody(CodeMethod codeElement, CodeClass parentClass, string returnType, LanguageWriter writer)
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ private void WriteIndexerBody(CodeMethod codeElement, CodeClass parentClass, Lan
if (parentClass.GetPropertyOfKind(CodePropertyKind.PathParameters) is CodeProperty pathParametersProperty &&
codeElement.OriginalIndexer != null)
writer.WriteLines($"{conventions.TempDictionaryVarName} = @{pathParametersProperty.NamePrefix}{pathParametersProperty.Name.ToSnakeCase()}.clone",
$"{conventions.TempDictionaryVarName}[\"{codeElement.OriginalIndexer.SerializationName}\"] = {codeElement.OriginalIndexer.IndexParameterName.ToSnakeCase()}");
$"{conventions.TempDictionaryVarName}[\"{codeElement.OriginalIndexer.IndexParameter.SerializationName}\"] = {codeElement.OriginalIndexer.IndexParameter.Name.ToSnakeCase()}");
conventions.AddRequestBuilderBody(parentClass, returnType, writer, conventions.TempDictionaryVarName, $"return {prefix}");
}
private void WriteDeserializerBody(CodeClass parentClass, LanguageWriter writer)
Expand Down
Loading
Loading