Skip to content

Commit

Permalink
Merge pull request #3071 from microsoft/feature/index-parameter-descr…
Browse files Browse the repository at this point in the history
…iption

feature/index parameter description
  • Loading branch information
baywet authored Aug 8, 2023
2 parents 5491844 + 3796408 commit 6f49e56
Show file tree
Hide file tree
Showing 29 changed files with 255 additions and 184 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added backing store support for Python. [#2858](https://github.com/microsoft/kiota/issues/2858)

- 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 IEnumerable<CodeType> GetUnmappedTypeDefinitions(CodeElement codeElement
};
}
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 @@ private CodeType GetIndexerParameterType(OpenApiUrlTreeNode currentNode, OpenApi
_ => 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 @@ private CodeIndexer[] CreateIndexer(string childIdentifier, string childType, Co
{
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
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,7 +690,7 @@ protected static void MoveClassesWithNamespaceNamesUnderNamespace(CodeElement cu
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 &&
Expand All @@ -699,18 +699,18 @@ protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentE
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

0 comments on commit 6f49e56

Please sign in to comment.