Skip to content

Commit

Permalink
Merge pull request #3212 from microsoft/feature/with-url
Browse files Browse the repository at this point in the history
feature/with url
  • Loading branch information
baywet authored Aug 29, 2023
2 parents 1353e09 + a672d27 commit 9d206b8
Show file tree
Hide file tree
Showing 27 changed files with 305 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added support for raw URL in the fluent API surface in CSharp, Go, Java, PHP, Python, Ruby, TypeScript. [#3199](https://github.com/microsoft/kiota/issues/3199)
- Added support for external documentation links within descriptions in Python. [#2041](https://github.com/microsoft/kiota/issues/2041)
- Added support for API manifests. [#3104](https://github.com/microsoft/kiota/issues/3104)
- Added support for reserved path parameters. [#2320](https://github.com/microsoft/kiota/issues/2320)
Expand Down
4 changes: 4 additions & 0 deletions src/Kiota.Builder/CodeDOM/CodeClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ public override void RemoveChildElementByName(params string[] names)
else throw new InvalidOperationException($"The element {name} could not be found in the class {Name}");
}
}
public void RemoveMethodByKinds(params CodeMethodKind[] kinds)
{
RemoveChildElementByName(InnerChildElements.Where(x => x.Value is CodeMethod method && method.IsOfKind(kinds)).Select(static x => x.Key).ToArray());
}
private string ResolveUniquePropertyName(string name)
{
if (FindPropertyByNameInTypeHierarchy(name) == null)
Expand Down
4 changes: 4 additions & 0 deletions src/Kiota.Builder/CodeDOM/CodeMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public enum CodeMethodKind
/// Method used to distinguish between regular and composed type wrapper models during serialization for loosely-typed languages.
/// </summary>
ComposedTypeMarker,
/// <summary>
/// Fluent API method returning a request builder with a set raw URL. depends on the RawUrlConstructor.
/// </summary>
RawUrlBuilder,
}
public enum HttpMethod
{
Expand Down
55 changes: 55 additions & 0 deletions src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ private void CreateRequestBuilderClass(CodeNamespace currentNamespace, OpenApiUr
// Add methods for Operations
if (currentNode.HasOperations(Constants.DefaultOpenApiLabel))
{
CreateWithUrlMethod(currentNode, codeClass);
foreach (var operation in currentNode
.PathItems[Constants.DefaultOpenApiLabel]
.Operations)
Expand All @@ -783,6 +784,41 @@ private void CreateRequestBuilderClass(CodeNamespace currentNamespace, OpenApiUr
}
});
}
private static void CreateWithUrlMethod(OpenApiUrlTreeNode currentNode, CodeClass currentClass)
{
var methodToAdd = new CodeMethod
{
Name = "WithUrl",
Kind = CodeMethodKind.RawUrlBuilder,
Documentation = new()
{
Description = "Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.",
},
Access = AccessModifier.Public,
IsAsync = false,
IsStatic = false,
ReturnType = new CodeType
{
ActionOf = false,
IsExternal = false,
IsNullable = false,
TypeDefinition = currentClass,
},
Deprecation = currentNode.GetDeprecationInformation(),
};
methodToAdd.AddParameter(new CodeParameter
{
Name = "rawUrl",
Type = new CodeType { Name = "string", IsExternal = true },
Optional = false,
Documentation = new()
{
Description = "The raw URL to use for the request builder.",
},
Kind = CodeParameterKind.RawUrl,
});
currentClass.AddMethod(methodToAdd);
}
private static void CreateMethod(string propIdentifier, string propType, CodeClass codeClass, OpenApiUrlTreeNode currentNode)
{
var methodToAdd = new CodeMethod
Expand Down Expand Up @@ -960,6 +996,25 @@ private void CreateUrlManagement(CodeClass currentClass, OpenApiUrlTreeNode curr
constructor.AddParameter(backingStoreParam);
}
currentClass.AddMethod(constructor);
if (!isApiClientClass)
{
var overloadCtor = (CodeMethod)constructor.Clone();
overloadCtor.Kind = CodeMethodKind.RawUrlConstructor;
overloadCtor.OriginalMethod = constructor;
overloadCtor.RemoveParametersByKind(CodeParameterKind.PathParameters, CodeParameterKind.Path);
overloadCtor.AddParameter(new CodeParameter
{
Name = "rawUrl",
Type = new CodeType { Name = "string", IsExternal = true },
Optional = false,
Documentation = new()
{
Description = "The raw URL to use for the request builder.",
},
Kind = CodeParameterKind.RawUrl,
});
currentClass.AddMethod(overloadCtor);
}
}
private static readonly Func<CodeClass, int> shortestNamespaceOrder = x => x.GetNamespaceDepth();
/// <summary>
Expand Down
1 change: 0 additions & 1 deletion src/Kiota.Builder/Refiners/CSharpRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
"IComposedTypeWrapper"
);
cancellationToken.ThrowIfCancellationRequested();
AddRawUrlConstructorOverload(generatedCode);
AddPropertiesAndMethodTypesImports(generatedCode, false, false, false);
AddAsyncSuffix(generatedCode);
cancellationToken.ThrowIfCancellationRequested();
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/Refiners/CliRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
IsExternal = true
}
});
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlBuilder);
RemoveBackwardCompatibleIndexers(generatedCode);
RemoveRequestConfigurationClasses(generatedCode,
new CodeUsing
Expand Down
36 changes: 13 additions & 23 deletions src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -617,12 +617,14 @@ protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentE
}
else
{
if (indexerParentClass.GetChildElements(true).OfType<CodeIndexer>().FirstOrDefault(static x => x.IsLegacyIndexer) is CodeIndexer legacyIndexer)
var foundLegacyIndexer = indexerParentClass.Methods.Any(x => x.Kind is CodeMethodKind.IndexerBackwardCompatibility && x.OriginalIndexer is not null && x.OriginalIndexer.IsLegacyIndexer);
if (!foundLegacyIndexer && indexerParentClass.GetChildElements(true).OfType<CodeIndexer>().FirstOrDefault(static x => x.IsLegacyIndexer) is CodeIndexer legacyIndexer)
{
indexerParentClass.RemoveChildElement(legacyIndexer);
indexerParentClass.AddMethod(CodeMethod.FromIndexer(legacyIndexer, methodNameCallback, parameterNameCallback, parameterNullable));
foundLegacyIndexer = true;
}
indexerParentClass.AddMethod(CodeMethod.FromIndexer(currentIndexer, methodNameCallback, parameterNameCallback, parameterNullable, true));
indexerParentClass.AddMethod(CodeMethod.FromIndexer(currentIndexer, methodNameCallback, parameterNameCallback, parameterNullable, foundLegacyIndexer));
}
}
else if (!currentIndexer.IsLegacyIndexer)
Expand Down Expand Up @@ -787,31 +789,19 @@ protected static void MakeModelPropertiesNullable(CodeElement currentElement)
.ForEach(static x => x.Type.IsNullable = true);
CrawlTree(currentElement, MakeModelPropertiesNullable);
}
protected static void AddRawUrlConstructorOverload(CodeElement currentElement)
protected static void RemoveMethodByKind(CodeElement currentElement, CodeMethodKind kind, params CodeMethodKind[] additionalKinds)
{
if (currentElement is CodeMethod currentMethod &&
currentMethod.IsOfKind(CodeMethodKind.Constructor) &&
RemoveMethodByKindImpl(currentElement, new List<CodeMethodKind>(additionalKinds) { kind }.ToArray());
}
private static void RemoveMethodByKindImpl(CodeElement currentElement, CodeMethodKind[] kinds)
{
if (currentElement is CodeMethod codeMethod &&
currentElement.Parent is CodeClass parentClass &&
parentClass.IsOfKind(CodeClassKind.RequestBuilder))
codeMethod.IsOfKind(kinds))
{
var overloadCtor = (CodeMethod)currentMethod.Clone();
overloadCtor.Kind = CodeMethodKind.RawUrlConstructor;
overloadCtor.OriginalMethod = currentMethod;
overloadCtor.RemoveParametersByKind(CodeParameterKind.PathParameters, CodeParameterKind.Path);
overloadCtor.AddParameter(new CodeParameter
{
Name = "rawUrl",
Type = new CodeType { Name = "string", IsExternal = true },
Optional = false,
Documentation = new()
{
Description = "The raw URL to use for the request builder.",
},
Kind = CodeParameterKind.RawUrl,
});
parentClass.AddMethod(overloadCtor);
parentClass.RemoveMethodByKinds(codeMethod.Kind);
}
CrawlTree(currentElement, AddRawUrlConstructorOverload);
CrawlTree(currentElement, x => RemoveMethodByKindImpl(x, kinds));
}
protected static void RemoveCancellationParameter(CodeElement currentElement)
{
Expand Down
9 changes: 6 additions & 3 deletions src/Kiota.Builder/Refiners/GoRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
string.Empty,
"GetIsComposedType"
);
AddRawUrlConstructorOverload(
generatedCode
);
cancellationToken.ThrowIfCancellationRequested();
RemoveModelPropertiesThatDependOnSubNamespaces(
generatedCode
Expand Down Expand Up @@ -590,6 +587,12 @@ private static void CorrectMethodType(CodeMethod currentMethod)
if (currentMethod.IsOfKind(CodeMethodKind.Factory))
currentMethod.ReturnType = new CodeType { Name = "Parsable", IsNullable = false, IsExternal = true };
}
else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlBuilder))
{
currentMethod.ReturnType.IsNullable = true;
if (currentMethod.Parameters.OfKind(CodeParameterKind.RawUrl) is CodeParameter codeParameter)
codeParameter.Type.IsNullable = false;
}
CorrectCoreTypes(parentClass, DateTypesReplacements, currentMethod.Parameters
.Select(static x => x.Type)
.Union(new[] { currentMethod.ReturnType })
Expand Down
1 change: 0 additions & 1 deletion src/Kiota.Builder/Refiners/JavaRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
SerializationNamespaceName,
"ComposedTypeWrapper"
);
AddRawUrlConstructorOverload(generatedCode);
CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements);
cancellationToken.ThrowIfCancellationRequested();
ReplaceBinaryByNativeType(generatedCode, "InputStream", "java.io", true, true);
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/Refiners/PhpRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
{
return Task.Run(() =>
{
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor);
AddInnerClasses(generatedCode,
true,
string.Empty,
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/Refiners/PythonRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor);
AddDefaultImports(generatedCode, defaultUsingEvaluators);
DisableActionOf(generatedCode,
CodeParameterKind.RequestConfiguration);
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/Refiners/RubyRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor);
ReplaceIndexersByMethodsWithParameter(generatedCode,
false,
static x => $"by_{x.ToSnakeCase()}",
Expand Down
5 changes: 5 additions & 0 deletions src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor);
RemoveHandlerFromRequestBuilder(generatedCode);
ReplaceReservedNames(generatedCode, new TypeScriptReservedNamesProvider(), static x => $"{x}Escaped");
ReplaceReservedExceptionPropertyNames(generatedCode, new TypeScriptExceptionsReservedNamesProvider(), static x => $"{x}Escaped");
Expand Down Expand Up @@ -304,6 +305,10 @@ private static void CorrectMethodType(CodeMethod currentMethod)
}
else if (currentMethod.IsOfKind(CodeMethodKind.Factory) && currentMethod.Parameters.OfKind(CodeParameterKind.ParseNode) is CodeParameter parseNodeParam)
parseNodeParam.Type.Name = parseNodeParam.Type.Name[1..];
else if (currentMethod.IsOfKind(CodeMethodKind.RawUrlBuilder) && currentMethod.Parameters.OfKind(CodeParameterKind.RawUrl) is { } parameter)
{
parameter.Type.IsNullable = false;
}
CorrectCoreTypes(currentMethod.Parent as CodeClass, DateTypesReplacements, currentMethod.Parameters
.Select(x => x.Type)
.Union(new[] { currentMethod.ReturnType })
Expand Down
9 changes: 9 additions & 0 deletions src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w
WriteConstructorBody(parentClass, codeElement, writer);
WriteApiConstructorBody(parentClass, codeElement, writer);
break;
case CodeMethodKind.RawUrlBuilder:
WriteRawUrlBuilderBody(parentClass, codeElement, writer);
break;
case CodeMethodKind.Constructor:
case CodeMethodKind.RawUrlConstructor:
WriteConstructorBody(parentClass, codeElement, writer);
Expand Down Expand Up @@ -97,6 +100,12 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w
break;
}
}
private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer)
{
var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter");
var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property");
writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterUpperCase()});");
}
private static readonly CodePropertyTypeComparer CodePropertyTypeForwardComparer = new();
private static readonly CodePropertyTypeComparer CodePropertyTypeBackwardComparer = new(true);
private void WriteFactoryMethodBodyForInheritedModel(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer)
Expand Down
12 changes: 11 additions & 1 deletion src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
case CodeMethodKind.Setter:
WriteSetterBody(codeElement, writer, parentClass);
break;
case CodeMethodKind.RawUrlBuilder:
WriteRawUrlBuilderBody(parentClass, codeElement, writer);
break;
case CodeMethodKind.ClientConstructor:
WriteConstructorBody(parentClass, codeElement, writer, inherits);
WriteApiConstructorBody(parentClass, codeElement, writer);
Expand Down Expand Up @@ -81,6 +84,12 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
}
writer.CloseBlock();
}
private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer)
{
var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter");
var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property");
writer.WriteLine($"return New{parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, m.BaseRequestBuilder.{requestAdapterProperty.Name.ToFirstCharacterUpperCase()});");
}
private void WriteComposedTypeMarkerBody(LanguageWriter writer)
{
writer.WriteLine("return true");
Expand Down Expand Up @@ -412,7 +421,8 @@ private void WriteMethodPrototype(CodeMethod code, CodeElement parentBlock, Lang
CodeMethodKind.RequestBuilderWithParameters,
CodeMethodKind.RequestBuilderBackwardCompatibility,
CodeMethodKind.RawUrlConstructor,
CodeMethodKind.ComposedTypeMarker) || code.IsAsync ?
CodeMethodKind.ComposedTypeMarker,
CodeMethodKind.RawUrlBuilder) || code.IsAsync ?
string.Empty :
"error";
if (!string.IsNullOrEmpty(finalReturnType) && !string.IsNullOrEmpty(errorDeclaration))
Expand Down
9 changes: 9 additions & 0 deletions src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
case CodeMethodKind.Setter:
WriteSetterBody(codeElement, writer, parentClass);
break;
case CodeMethodKind.RawUrlBuilder:
WriteRawUrlBuilderBody(parentClass, codeElement, writer);
break;
case CodeMethodKind.ClientConstructor:
WriteConstructorBody(parentClass, codeElement, writer, inherits);
WriteApiConstructorBody(parentClass, codeElement, writer);
Expand Down Expand Up @@ -88,6 +91,12 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
}
writer.CloseBlock();
}
private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer)
{
var rawUrlParameter = codeElement.Parameters.OfKind(CodeParameterKind.RawUrl) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RawUrl parameter");
var requestAdapterProperty = parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) ?? throw new InvalidOperationException("RawUrlBuilder method should have a RequestAdapter property");
writer.WriteLine($"return new {parentClass.Name.ToFirstCharacterUpperCase()}({rawUrlParameter.Name.ToFirstCharacterLowerCase()}, {requestAdapterProperty.Name.ToFirstCharacterLowerCase()});");
}
private const string ResultVarName = "result";
private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer)
{
Expand Down
Loading

0 comments on commit 9d206b8

Please sign in to comment.