From b33c9ec2efc4f787721c741a433f3d75203b6c5f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 19 Aug 2021 16:24:34 -0400 Subject: [PATCH 01/23] - updates typescript generation to add support for raw URLs --- abstractions/typescript/src/requestInfo.ts | 23 +++++++++++- src/Kiota.Builder/CodeDOM/CodeParameter.cs | 5 ++- src/Kiota.Builder/CodeDOM/CodeProperty.cs | 3 +- .../CodeParameterOrderComparer.cs | 36 +++++++++++++++++++ src/Kiota.Builder/KiotaBuilder.cs | 22 ++++++++++++ .../Writers/TypeScript/CodeMethodWriter.cs | 8 +++-- .../TypeScript/TypeScriptConventionService.cs | 7 ++-- 7 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 src/Kiota.Builder/CodeParameterOrderComparer.cs diff --git a/abstractions/typescript/src/requestInfo.ts b/abstractions/typescript/src/requestInfo.ts index 96d46f8789..8255a80a81 100644 --- a/abstractions/typescript/src/requestInfo.ts +++ b/abstractions/typescript/src/requestInfo.ts @@ -8,12 +8,33 @@ import { MiddlewareOption } from "./middlewareOption"; export class RequestInfo { /** The URI of the request. */ public URI?: string; + public setUri(currentPath: string, pathSegment: string, isRawUrl: boolean) : void { + if(isRawUrl) { + const questionMarkSplat = currentPath.split('?'); + const schemeHostAndPath = questionMarkSplat[0]; + this.URI = schemeHostAndPath; + if(questionMarkSplat.length > 1) { + const queryString = questionMarkSplat[1]; + queryString?.split('&').forEach(queryPair => { + const keyValue = queryPair.split('='); + if(keyValue.length > 1) { + const key = keyValue[0]; + if(key) { + this.queryParameters.set(key, keyValue[1]); + } + } + }); + } + } else { + this.URI = currentPath + pathSegment; + } + } /** The HTTP method for the request */ public httpMethod?: HttpMethod; /** The Request Body. */ public content?: ReadableStream; /** The Query Parameters of the request. */ - public queryParameters: Map = new Map(); //TODO: case insensitive + public queryParameters: Map = new Map(); //TODO: case insensitive /** The Request Headers. */ public headers: Map = new Map(); //TODO: case insensitive private _middlewareOptions = new Map(); //TODO: case insensitive diff --git a/src/Kiota.Builder/CodeDOM/CodeParameter.cs b/src/Kiota.Builder/CodeDOM/CodeParameter.cs index a5bcf9a394..cee43efcc6 100644 --- a/src/Kiota.Builder/CodeDOM/CodeParameter.cs +++ b/src/Kiota.Builder/CodeDOM/CodeParameter.cs @@ -15,7 +15,8 @@ public enum CodeParameterKind CurrentPath, Options, Serializer, - BackingStore + BackingStore, + RawUrl } public class CodeParameter : CodeTerminal, ICloneable, IDocumentedElement @@ -28,6 +29,7 @@ public CodeParameter(CodeElement parent): base(parent) public CodeTypeBase Type {get;set;} public bool Optional {get;set;}= false; public string Description {get; set;} + public string DefaultValue {get; set;} public bool IsOfKind(params CodeParameterKind[] kinds) { return kinds?.Contains(ParameterKind) ?? false; } @@ -39,6 +41,7 @@ public object Clone() Name = Name.Clone() as string, Type = Type?.Clone() as CodeTypeBase, Description = Description?.Clone() as string, + DefaultValue = DefaultValue?.Clone() as string, }; } } diff --git a/src/Kiota.Builder/CodeDOM/CodeProperty.cs b/src/Kiota.Builder/CodeDOM/CodeProperty.cs index 8cd23c1dae..04772b1845 100644 --- a/src/Kiota.Builder/CodeDOM/CodeProperty.cs +++ b/src/Kiota.Builder/CodeDOM/CodeProperty.cs @@ -11,7 +11,8 @@ public enum CodePropertyKind BackingStore, PathSegment, CurrentPath, - HttpCore + HttpCore, + RawUrl } public class CodeProperty : CodeTerminal, IDocumentedElement diff --git a/src/Kiota.Builder/CodeParameterOrderComparer.cs b/src/Kiota.Builder/CodeParameterOrderComparer.cs new file mode 100644 index 0000000000..3c1c1a71dc --- /dev/null +++ b/src/Kiota.Builder/CodeParameterOrderComparer.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace Kiota.Builder { + public class CodeParameterOrderComparer : IComparer + { + public int Compare(CodeParameter x, CodeParameter y) + { + return (x, y) switch { + (null, null) => 0, + (null, _) => -1, + (_, null) => 1, + _ => x.Optional.CompareTo(y.Optional) * optionalWeight + + getKindOrderHint(x.ParameterKind).CompareTo(getKindOrderHint(y.ParameterKind)) * kindWeight, + }; + } + private static int getKindOrderHint(CodeParameterKind kind) { + return kind switch { + CodeParameterKind.CurrentPath => 1, + CodeParameterKind.HttpCore => 2, + CodeParameterKind.RawUrl => 3, + CodeParameterKind.QueryParameter => 4, + CodeParameterKind.Headers => 5, + CodeParameterKind.Options => 6, + CodeParameterKind.ResponseHandler => 7, + CodeParameterKind.Serializer => 8, + CodeParameterKind.BackingStore => 9, + CodeParameterKind.Custom => 12, + CodeParameterKind.RequestBody => 11, + CodeParameterKind.SetterValue => 10, + _ => 13, + }; + } + private static int optionalWeight = 1000; + private static int kindWeight = 10; + } +} diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 8a3ea30946..f1aa2c1d99 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -278,6 +278,7 @@ private void CreateRequestBuilderClass(CodeNamespace currentNamespace, OpenApiUr }); } private static readonly string currentPathParameterName = "currentPath"; + private static readonly string rawUrlParameterName = "isRawUrl"; private void CreatePathManagement(CodeClass currentClass, OpenApiUrlTreeNode currentNode, bool isApiClientClass) { var pathProperty = new CodeProperty(currentClass) { Access = AccessModifier.Private, @@ -340,6 +341,27 @@ private void CreatePathManagement(CodeClass currentClass, OpenApiUrlTreeNode cur Description = currentPathProperty.Description, ParameterKind = CodeParameterKind.CurrentPath, }); + var isRawURLPproperty = new CodeProperty(constructor) { + Name = rawUrlParameterName, + Description = "Whether the current path is a raw URL", + PropertyKind = CodePropertyKind.RawUrl, + Access = AccessModifier.Private, + ReadOnly = true, + }; + isRawURLPproperty.Type = new CodeType(isRawURLPproperty) { + Name = "boolean", + IsExternal = true, + IsNullable = false, + }; + currentClass.AddProperty(isRawURLPproperty); + constructor.AddParameter(new CodeParameter(constructor) { + Name = rawUrlParameterName, + Type = isRawURLPproperty.Type, + Optional = true, + Description = isRawURLPproperty.Description, + ParameterKind = CodeParameterKind.RawUrl, + DefaultValue = "true", + }); } constructor.AddParameter(new CodeParameter(constructor) { Name = httpCoreParameterName, diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs index 87f31304e9..22a6b1791a 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs @@ -103,6 +103,7 @@ private static void WriteConstructorBody(CodeClass parentClass, CodeMethod curre if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.HttpCore, CodePropertyKind.HttpCore, writer); AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.CurrentPath, CodePropertyKind.CurrentPath, writer); + AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RawUrl, CodePropertyKind.RawUrl, writer); } } private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMethod currentMethod, CodeParameterKind parameterKind, CodePropertyKind propertyKind, LanguageWriter writer) { @@ -181,8 +182,8 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, CodeParameter req if(codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null"); writer.WriteLines($"const {requestInfoVarName} = new RequestInfo();", - $"{requestInfoVarName}.URI = (this.{localConventions.CurrentPathPropertyName} ?? '') + this.{localConventions.PathSegmentPropertyName},", - $"{requestInfoVarName}.httpMethod = HttpMethod.{codeElement.HttpMethod.ToString().ToUpperInvariant()},"); + $"{requestInfoVarName}.setUri(this.{localConventions.CurrentPathPropertyName}, this.{localConventions.PathSegmentPropertyName}, this.{localConventions.RawUrlPropertyName});", + $"{requestInfoVarName}.httpMethod = HttpMethod.{codeElement.HttpMethod.ToString().ToUpperInvariant()};"); if(headersParam != null) writer.WriteLine($"{headersParam.Name} && {requestInfoVarName}.setHeadersFromRawObject(h);"); if(queryStringParam != null) @@ -227,6 +228,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer, bo writer.WriteLine(localConventions.DocCommentEnd); } } + private static CodeParameterOrderComparer parameterOrderComparer = new CodeParameterOrderComparer(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string returnType, bool isVoid) { var accessModifier = localConventions.GetAccessModifier(code.Access); var methodName = (code.MethodKind switch { @@ -235,7 +237,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string _ => code.Name, })?.ToFirstCharacterLowerCase(); var asyncPrefix = code.IsAsync && code.MethodKind != CodeMethodKind.RequestExecutor ? " async ": string.Empty; - var parameters = string.Join(", ", code.Parameters.Select(p=> localConventions.GetParameterSignature(p)).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p=> localConventions.GetParameterSignature(p)).ToList()); var asyncReturnTypePrefix = code.IsAsync ? "Promise<": string.Empty; var asyncReturnTypeSuffix = code.IsAsync ? ">": string.Empty; var nullableSuffix = code.ReturnType.IsNullable && !isVoid ? " | undefined" : string.Empty; diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index e2ce4c6ad2..6d45505eb5 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -24,11 +24,13 @@ public TypeScriptConventionService(LanguageWriter languageWriter) public string ParseNodeInterfaceName => "ParseNode"; + public object RawUrlPropertyName => "isRawUrl"; + internal string DocCommentStart = "/**"; internal string DocCommentEnd = " */"; internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, LanguageWriter writer, string suffix = default) { var currentPath = addCurrentPath ? $"this.{CurrentPathPropertyName} + " : string.Empty; - writer.WriteLines($"return new {returnType}({currentPath}this.{PathSegmentPropertyName}{suffix}, this.{HttpCorePropertyName});"); + writer.WriteLines($"return new {returnType}({currentPath}this.{PathSegmentPropertyName}{suffix}, this.{HttpCorePropertyName}, false);"); } public string GetAccessModifier(AccessModifier access) @@ -42,7 +44,8 @@ public string GetAccessModifier(AccessModifier access) public string GetParameterSignature(CodeParameter parameter) { - return $"{parameter.Name}{(parameter.Optional ? "?" : string.Empty)}: {GetTypeString(parameter.Type)}{(parameter.Type.IsNullable ? " | undefined": string.Empty)}"; + var defaultValueSuffiix = string.IsNullOrEmpty(parameter.DefaultValue) ? string.Empty : $" = {parameter.DefaultValue}"; + return $"{parameter.Name}{(parameter.Optional && parameter.Type.IsNullable ? "?" : string.Empty)}: {GetTypeString(parameter.Type)}{(parameter.Type.IsNullable ? " | undefined": string.Empty)}{defaultValueSuffiix}"; } public string GetTypeString(CodeTypeBase code) From 4a4379af1aec87d91e4032f778486f563adfa7b8 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Aug 2021 10:50:12 -0400 Subject: [PATCH 02/23] - removes dependency on lodash in abstractions package --- abstractions/typescript/package-lock.json | 11 ----------- abstractions/typescript/package.json | 2 -- .../typescript/src/store/inMemoryBackingStore.ts | 12 +++++++----- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/abstractions/typescript/package-lock.json b/abstractions/typescript/package-lock.json index 3c98f0ab6b..2137789333 100644 --- a/abstractions/typescript/package-lock.json +++ b/abstractions/typescript/package-lock.json @@ -4,12 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/lodash": { - "version": "4.14.172", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.172.tgz", - "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==", - "dev": true - }, "@types/node": { "version": "16.7.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.1.tgz", @@ -22,11 +16,6 @@ "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==", "dev": true }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "typescript": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", diff --git a/abstractions/typescript/package.json b/abstractions/typescript/package.json index f76f762903..35a3ebe382 100644 --- a/abstractions/typescript/package.json +++ b/abstractions/typescript/package.json @@ -23,7 +23,6 @@ }, "homepage": "https://github.com/microsoft/kiota#readme", "devDependencies": { - "@types/lodash": "^4.14.172", "@types/node": "^16.7.1", "@types/uuid": "^8.3.1", "typescript": "^4.3.5" @@ -32,7 +31,6 @@ "registry": "https://npm.pkg.github.com" }, "dependencies": { - "lodash": "^4.17.21", "uuid": "^8.3.2", "web-streams-polyfill": "^3.1.0" } diff --git a/abstractions/typescript/src/store/inMemoryBackingStore.ts b/abstractions/typescript/src/store/inMemoryBackingStore.ts index d179b47b86..36c32162ec 100644 --- a/abstractions/typescript/src/store/inMemoryBackingStore.ts +++ b/abstractions/typescript/src/store/inMemoryBackingStore.ts @@ -1,5 +1,4 @@ import { BackingStore } from "./backingStore"; -import _ from "lodash"; import { v4 as uuidv4 } from 'uuid'; type storeEntryWrapper = {changed: boolean, value: unknown}; @@ -34,10 +33,13 @@ export class InMemoryBackingStore implements BackingStore { }); } public enumerate(): storeEntry[] { - return _.map(this.returnOnlyChangedValues ? - _.filter(this.store, (_, k) => this.store.get(k)?.changed ?? false) : - this.store, - (_, k) => { return { key: k, value: this.store.get(k)?.value}}); + let filterableArray = [...this.store.entries()]; + if(this.returnOnlyChangedValues) { + filterableArray = filterableArray.filter(([_, v]) => v.changed); + } + return filterableArray.map(([key, value]) => { + return {key, value}; + }); } public enumerateKeysForValuesChangedToNull(): string[] { const keys: string[] = []; From 454a5feb392a4864ae09638b2956fab343ff40be Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Aug 2021 11:01:15 -0400 Subject: [PATCH 03/23] - adds the missing doc comment for set URI method --- abstractions/typescript/src/requestInfo.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/abstractions/typescript/src/requestInfo.ts b/abstractions/typescript/src/requestInfo.ts index 8255a80a81..e84c1a61b5 100644 --- a/abstractions/typescript/src/requestInfo.ts +++ b/abstractions/typescript/src/requestInfo.ts @@ -8,6 +8,12 @@ import { MiddlewareOption } from "./middlewareOption"; export class RequestInfo { /** The URI of the request. */ public URI?: string; + /** + * Sets the URI of the request. + * @param currentPath the current path (scheme, host, port, path, query parameters) of the request. + * @param pathSegment the segment to append to the current path. + * @param isRawUrl whether the path segment is a raw url. When true, the segment is not happened and the current path is parsed for query parameters. + */ public setUri(currentPath: string, pathSegment: string, isRawUrl: boolean) : void { if(isRawUrl) { const questionMarkSplat = currentPath.split('?'); From 29bd01699ca7d06f71b7835f065321aaad7afdec Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Aug 2021 13:06:16 -0400 Subject: [PATCH 04/23] - adds support for raw urls in dotnet --- abstractions/dotnet/src/RequestInfo.cs | 19 +++++++++++++++++++ .../Writers/CSharp/CSharpConventionService.cs | 10 ++++++++-- .../Writers/CSharp/CodeMethodWriter.cs | 10 ++++++---- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/abstractions/dotnet/src/RequestInfo.cs b/abstractions/dotnet/src/RequestInfo.cs index f56bd3b110..9d76795a01 100644 --- a/abstractions/dotnet/src/RequestInfo.cs +++ b/abstractions/dotnet/src/RequestInfo.cs @@ -20,6 +20,25 @@ public class RequestInfo /// public Uri URI { get; set; } /// + /// Sets the URI of the request. + /// + /// the current path (scheme, host, port, path, query parameters) of the request. + /// the segment to append to the current path. + /// whether the path segment is a raw url. When true, the segment is not happened and the current path is parsed for query parameters. + public void SetURI(string currentPath, string pathSegment, bool isRawUrl) { + if (isRawUrl) { + if(string.IsNullOrEmpty(currentPath)) + throw new ArgumentNullException(nameof(currentPath)); + var parseUri = new Uri(currentPath); + foreach(var qsp in parseUri.Query.Split('&').Select(x => x.Split('='))) { + QueryParameters.Add(qsp[0], qsp[1]); + } + URI = new Uri($"{parseUri.Scheme}://{parseUri.Host}:{parseUri.Port}/{parseUri.PathAndQuery.Split('?').First()}"); + } else { + URI = new Uri(currentPath + pathSegment); + } + } + /// /// The HTTP method of the request. /// public HttpMethod HttpMethod { get; set; } diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index 36921b1d75..2b1f372592 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -14,6 +14,7 @@ public class CSharpConventionService : ILanguageConventionService { public HashSet NullableTypes { get; } = new() { "int", "bool", "float", "double", "decimal", "Guid", "DateTimeOffset" }; public static string NullableMarker => "?"; public string ParseNodeInterfaceName => "IParseNode"; + public object RawUrlPropertyName => "IsRawUrl"; public void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) writer.WriteLine($"{DocCommentPrefix}{description}"); @@ -28,7 +29,7 @@ public string GetAccessModifier(AccessModifier access) } internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, LanguageWriter writer, string suffix = default, string prefix = default) { var currentPath = addCurrentPath ? $"{CurrentPathPropertyName} + " : string.Empty; - writer.WriteLine($"{prefix}new {returnType}({currentPath}{PathSegmentPropertyName} {suffix}, {HttpCorePropertyName});"); + writer.WriteLine($"{prefix}new {returnType}({currentPath}{PathSegmentPropertyName} {suffix}, {HttpCorePropertyName}, false);"); } internal bool ShouldTypeHaveNullableMarker(CodeTypeBase propType, string propTypeName) { return propType.IsNullable && (NullableTypes.Contains(propTypeName) || (propType is CodeType codeType && codeType.TypeDefinition is CodeEnum)); @@ -74,7 +75,12 @@ public bool IsPrimitiveType(string typeName) { public string GetParameterSignature(CodeParameter parameter) { var parameterType = GetTypeString(parameter.Type); - return $"{parameterType} {parameter.Name}{(parameter.Optional ? $" = default": string.Empty)}"; + var defaultValue = (parameter) switch { + _ when !string.IsNullOrEmpty(parameter.DefaultValue) => $" = {parameter.DefaultValue}", + _ when parameter.Optional => " = default", + _ => string.Empty, + }; + return $"{parameterType} {parameter.Name}{defaultValue}"; } } } diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs index 9e4bf58be4..4dafc42e2e 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -91,6 +91,7 @@ private static void WriteConstructorBody(CodeClass parentClass, CodeMethod curre if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.HttpCore, CodePropertyKind.HttpCore, writer); AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.CurrentPath, CodePropertyKind.CurrentPath, writer); + AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RawUrl, CodePropertyKind.RawUrl, writer); } } private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMethod currentMethod, CodeParameterKind parameterKind, CodePropertyKind propertyKind, LanguageWriter writer) { @@ -160,10 +161,10 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, CodeParameter req var operationName = codeElement.HttpMethod.ToString(); writer.WriteLine($"var {_requestInfoVarName} = new RequestInfo {{"); writer.IncreaseIndent(); - writer.WriteLines($"HttpMethod = HttpMethod.{operationName?.ToUpperInvariant()},", - $"URI = new Uri({conventions.CurrentPathPropertyName} + {conventions.PathSegmentPropertyName}),"); + writer.WriteLine($"HttpMethod = HttpMethod.{operationName?.ToUpperInvariant()},"); writer.DecreaseIndent(); - writer.WriteLine("};"); + writer.WriteLines("};", + $"{_requestInfoVarName}.SetURI({conventions.CurrentPathPropertyName}, {conventions.PathSegmentPropertyName}, {conventions.RawUrlPropertyName});"); if(requestBodyParam != null) { if(requestBodyParam.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase)) writer.WriteLine($"{_requestInfoVarName}.SetStreamContent({requestBodyParam.Name});"); @@ -217,6 +218,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { writer.WriteLine($"{conventions.DocCommentPrefix}"); } } + private static CodeParameterOrderComparer parameterOrderComparer = new CodeParameterOrderComparer(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string returnType, bool inherits, bool isVoid) { var staticModifier = code.IsStatic ? "static " : string.Empty; var hideModifier = inherits && code.IsSerializationMethod ? "new " : string.Empty; @@ -234,7 +236,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string var baseSuffix = string.Empty; if(isConstructor && inherits) baseSuffix = " : base()"; - var parameters = string.Join(", ", code.Parameters.Select(p=> conventions.GetParameterSignature(p)).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p=> conventions.GetParameterSignature(p)).ToList()); var methodName = isConstructor ? code.Parent.Name.ToFirstCharacterUpperCase() : code.Name; writer.WriteLine($"{conventions.GetAccessModifier(code.Access)} {staticModifier}{hideModifier}{completeReturnType}{methodName}({parameters}){baseSuffix} {{"); } From 91f3246bdb0d6f7ac02b46ced90d1984f5814ac4 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Aug 2021 15:20:49 -0400 Subject: [PATCH 05/23] - minor defenseive programing adjustements --- abstractions/dotnet/src/RequestInfo.cs | 6 +++--- abstractions/typescript/src/requestInfo.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/abstractions/dotnet/src/RequestInfo.cs b/abstractions/dotnet/src/RequestInfo.cs index 9d76795a01..4641d4b2e8 100644 --- a/abstractions/dotnet/src/RequestInfo.cs +++ b/abstractions/dotnet/src/RequestInfo.cs @@ -30,10 +30,10 @@ public void SetURI(string currentPath, string pathSegment, bool isRawUrl) { if(string.IsNullOrEmpty(currentPath)) throw new ArgumentNullException(nameof(currentPath)); var parseUri = new Uri(currentPath); - foreach(var qsp in parseUri.Query.Split('&').Select(x => x.Split('='))) { - QueryParameters.Add(qsp[0], qsp[1]); + foreach(var qsp in parseUri.Query.Split('&').Select(x => x.Split('=')).Where(x => !string.IsNullOrEmpty(x[0]))) { + QueryParameters.Add(qsp[0], qsp.Length > 1 ? qsp[1] : null); } - URI = new Uri($"{parseUri.Scheme}://{parseUri.Host}:{parseUri.Port}/{parseUri.PathAndQuery.Split('?').First()}"); + URI = new Uri(parseUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped)); } else { URI = new Uri(currentPath + pathSegment); } diff --git a/abstractions/typescript/src/requestInfo.ts b/abstractions/typescript/src/requestInfo.ts index e84c1a61b5..5148a4ea0d 100644 --- a/abstractions/typescript/src/requestInfo.ts +++ b/abstractions/typescript/src/requestInfo.ts @@ -23,10 +23,10 @@ export class RequestInfo { const queryString = questionMarkSplat[1]; queryString?.split('&').forEach(queryPair => { const keyValue = queryPair.split('='); - if(keyValue.length > 1) { + if(keyValue.length > 0) { const key = keyValue[0]; if(key) { - this.queryParameters.set(key, keyValue[1]); + this.queryParameters.set(key, keyValue.length > 1 ? keyValue[1] : undefined); } } }); From 9e03e3dc7af40e857736d3b634303983e1120104 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 20 Aug 2021 15:35:56 -0400 Subject: [PATCH 06/23] - adds set URI method to java abstractions --- .../java/com/microsoft/kiota/RequestInfo.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java index 836637672c..6c3b6619ab 100644 --- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java +++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java @@ -1,6 +1,7 @@ package com.microsoft.kiota; import java.net.URI; +import java.net.URISyntaxException; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -21,6 +22,41 @@ public class RequestInfo { /** The URI of the request. */ @Nullable public URI uri; + /** + * Sets the URI of the request. + * @param currentPath the current path (scheme, host, port, path, query parameters) of the request. + * @param pathSegment the segment to append to the current path. + * @param isRawUrl whether the path segment is a raw url. When true, the segment is not happened and the current path is parsed for query parameters. + */ + public void setUri(@Nullable final String currentPath, @Nullable final String pathSegment, final boolean isRawUrl) { + if (isRawUrl) { + if(currentPath == null || currentPath.isEmpty()) { + throw new IllegalArgumentException("currentPath cannot be null or empty"); + } + final var questionMarkSplat = currentPath.split("?"); + final var schemeHostAndPath = questionMarkSplat[0]; + this.setUriFromString(schemeHostAndPath); + if (questionMarkSplat.length > 1) { + final var queryString = questionMarkSplat[1]; + final var rawQueryParameters = queryString.split("&"); + for (var queryParameter : rawQueryParameters) { + final var queryParameterNameValue = queryParameter.split("="); + if (!queryParameterNameValue[0].isEmpty()) { + this.queryParameters.put(queryParameterNameValue[0], queryParameterNameValue.length > 1 ? queryParameterNameValue[1] : null); + } + } + } + } else { + this.setUriFromString(currentPath + pathSegment); + } + } + private void setUriFromString(final String uriString) { + try { + this.uri = new URI(uriString); + } catch (final URISyntaxException e) { + throw new RuntimeException(e); + } + } /** The HTTP method for the request */ @Nullable public HttpMethod httpMethod; From 208ea74f26dd8ae562f2125047455338c84fa2d8 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 09:58:33 -0400 Subject: [PATCH 07/23] - code linting --- src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs | 2 +- .../Writers/TypeScript/TypeScriptConventionService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index 2b1f372592..d5dde5b8db 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -14,7 +14,7 @@ public class CSharpConventionService : ILanguageConventionService { public HashSet NullableTypes { get; } = new() { "int", "bool", "float", "double", "decimal", "Guid", "DateTimeOffset" }; public static string NullableMarker => "?"; public string ParseNodeInterfaceName => "IParseNode"; - public object RawUrlPropertyName => "IsRawUrl"; + public string RawUrlPropertyName => "IsRawUrl"; public void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) writer.WriteLine($"{DocCommentPrefix}{description}"); diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 6d45505eb5..b5fe5fe165 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -24,7 +24,7 @@ public TypeScriptConventionService(LanguageWriter languageWriter) public string ParseNodeInterfaceName => "ParseNode"; - public object RawUrlPropertyName => "isRawUrl"; + public string RawUrlPropertyName => "isRawUrl"; internal string DocCommentStart = "/**"; internal string DocCommentEnd = " */"; From d1ac70afc8d1fb7647dbde5eb8ee3a3bc63c03c9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 12:42:20 -0400 Subject: [PATCH 08/23] - updates java generation to support raw url --- .../Refiners/CommonLanguageRefiner.cs | 20 +++++++------- src/Kiota.Builder/Refiners/GoRefiner.cs | 1 + src/Kiota.Builder/Refiners/JavaRefiner.cs | 26 ++++++++++++++----- src/Kiota.Builder/Refiners/RubyRefiner.cs | 2 +- .../Refiners/TypeScriptRefiner.cs | 2 +- .../Writers/Java/CodeMethodWriter.cs | 10 ++++--- .../Writers/Java/JavaConventionService.cs | 16 +++++++----- 7 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 9c48e886d6..d9a0fce265 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -128,7 +128,7 @@ current.Parent is CodeClass parentClass && Access = AccessModifier.Public, IsAsync = false, MethodKind = CodeMethodKind.Getter, - ReturnType = currentProperty.Type, + ReturnType = currentProperty.Type.Clone() as CodeTypeBase, Description = $"Gets the {current.Name} property value. {currentProperty.Description}", AccessedProperty = currentProperty, }); @@ -142,14 +142,15 @@ current.Parent is CodeClass parentClass && AccessedProperty = currentProperty, }).First(); setter.ReturnType = new CodeType(setter) { - Name = "void" + Name = "void", + IsNullable = false, }; setter.Parameters.Add(new(setter) { Name = "value", ParameterKind = CodeParameterKind.SetterValue, Description = $"Value to set for the {current.Name} property.", Optional = parameterAsOptional, - Type = currentProperty.Type, + Type = currentProperty.Type.Clone() as CodeTypeBase, }); } } @@ -301,7 +302,7 @@ protected static void MoveClassesWithNamespaceNamesUnderNamespace(CodeElement cu } CrawlTree(currentElement, MoveClassesWithNamespaceNamesUnderNamespace); } - protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentElement, CodeNamespace rootNamespace, string methodNameSuffix = default) { + protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentElement, CodeNamespace rootNamespace, bool parameterNullable, string methodNameSuffix = default) { if(currentElement is CodeIndexer currentIndexer) { var currentParentClass = currentElement.Parent as CodeClass; currentParentClass.RemoveChildElement(currentElement); @@ -315,11 +316,12 @@ protected static void ReplaceIndexersByMethodsWithParameter(CodeElement currentE returnType.TypeDefinition as CodeClass, pathSegment.Trim('\"').TrimStart('/'), methodNameSuffix, - currentIndexer.Description); + currentIndexer.Description, + parameterNullable); } - CrawlTree(currentElement, c => ReplaceIndexersByMethodsWithParameter(c, rootNamespace, methodNameSuffix)); + CrawlTree(currentElement, c => ReplaceIndexersByMethodsWithParameter(c, rootNamespace, parameterNullable, methodNameSuffix)); } - private static void AddIndexerMethod(CodeElement currentElement, CodeClass targetClass, CodeClass indexerClass, string pathSegment, string methodNameSuffix, string description) { + private static void AddIndexerMethod(CodeElement currentElement, CodeClass targetClass, CodeClass indexerClass, string pathSegment, string methodNameSuffix, string description, bool parameterNullable) { if(currentElement is CodeProperty currentProperty && currentProperty.Type.AllTypes.Any(x => x.TypeDefinition == targetClass)) { var parentClass = currentElement.Parent as CodeClass; var method = new CodeMethod(parentClass) { @@ -344,13 +346,13 @@ private static void AddIndexerMethod(CodeElement currentElement, CodeClass targe }; parameter.Type = new CodeType(parameter) { Name = "String", - IsNullable = false, + IsNullable = parameterNullable, IsExternal = true, }; method.Parameters.Add(parameter); parentClass.AddMethod(method); } - CrawlTree(currentElement, c => AddIndexerMethod(c, targetClass, indexerClass, pathSegment, methodNameSuffix, description)); + CrawlTree(currentElement, c => AddIndexerMethod(c, targetClass, indexerClass, pathSegment, methodNameSuffix, description, parameterNullable)); } internal void AddInnerClasses(CodeElement current, bool prefixClassNameWithParentName) { if(current is CodeClass currentClass) { diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index da02902338..023cb6a1da 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -14,6 +14,7 @@ public override void Refine(CodeNamespace generatedCode) ReplaceIndexersByMethodsWithParameter( generatedCode, generatedCode, + false, "ById"); ReplaceRequestBuilderPropertiesByMethods( generatedCode diff --git a/src/Kiota.Builder/Refiners/JavaRefiner.cs b/src/Kiota.Builder/Refiners/JavaRefiner.cs index 81cc746775..d3c1c6c9da 100644 --- a/src/Kiota.Builder/Refiners/JavaRefiner.cs +++ b/src/Kiota.Builder/Refiners/JavaRefiner.cs @@ -11,7 +11,7 @@ public override void Refine(CodeNamespace generatedCode) { AddInnerClasses(generatedCode, false); AndInsertOverrideMethodForRequestExecutorsAndBuilders(generatedCode); - ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode); + ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, true); ConvertUnionTypesToWrapper(generatedCode); AddRequireNonNullImports(generatedCode); FixReferencesToEntityType(generatedCode); @@ -29,6 +29,7 @@ public override void Refine(CodeNamespace generatedCode) CodePropertyKind.AdditionalData, CodePropertyKind.BackingStore, }, _configuration.UsesBackingStore, true); + SetParametersToNullable(generatedCode, new Tuple(CodeMethodKind.Setter, CodePropertyKind.AdditionalData)); AddConstructorsForDefaultValues(generatedCode, true); CorrectCoreTypesForBackingStore(generatedCode, "com.microsoft.kiota.store", "BackingStoreFactorySingleton.instance.createBackingStore()"); ReplaceDefaultSerializationModules(generatedCode, "com.microsoft.kiota.serialization.JsonSerializationWriterFactory"); @@ -38,6 +39,12 @@ public override void Refine(CodeNamespace generatedCode) "com.microsoft.kiota.serialization.SerializationWriterFactoryRegistry" }, new [] { "com.microsoft.kiota.serialization.ParseNodeFactoryRegistry" }); } + private static void SetParametersToNullable(CodeElement currentElement, params Tuple[] accessorPairs) { + if(currentElement is CodeMethod method && + accessorPairs.Any(x => method.IsOfKind(x.Item1) && (method.AccessedProperty?.IsOfKind(x.Item2) ?? false))) + method.Parameters.ForEach(x => x.Type.IsNullable = true); + CrawlTree(currentElement, element => SetParametersToNullable(element, accessorPairs)); + } private static void AddEnumSetImport(CodeElement currentElement) { if(currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model) && currentClass.GetChildElements(true).OfType().Any(x => x.Type is CodeType xType && xType.TypeDefinition is CodeEnum xEnumType && xEnumType.Flags)) { @@ -83,7 +90,6 @@ private static void AddListImport(CodeElement currentElement) { new ("QueryParametersBase", "com.microsoft.kiota"), new ("MiddlewareOption", "com.microsoft.kiota"), new ("Map", "java.util"), - new ("URI", "java.net"), new ("URISyntaxException", "java.net"), new ("InputStream", "java.io"), new ("Function", "java.util.function"), @@ -100,8 +106,10 @@ private static void AddListImport(CodeElement currentElement) { new ("HashMap", "java.util"), }; private static void CorrectPropertyType(CodeProperty currentProperty) { - if(currentProperty.IsOfKind(CodePropertyKind.HttpCore)) - currentProperty.Type.Name = "HttpCore"; + if(currentProperty.IsOfKind(CodePropertyKind.HttpCore)) { + currentProperty.Type.Name = "HttpCore"; + currentProperty.Type.IsNullable = true; + } else if(currentProperty.IsOfKind(CodePropertyKind.BackingStore)) currentProperty.Type.Name = currentProperty.Type.Name[1..]; // removing the "I" else if("DateTimeOffset".Equals(currentProperty.Type.Name, StringComparison.OrdinalIgnoreCase)) { @@ -117,7 +125,8 @@ private static void CorrectPropertyType(CodeProperty currentProperty) { } else if(currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) { currentProperty.Type.Name = "Map"; currentProperty.DefaultValue = "new HashMap<>()"; - } + } else if(currentProperty.IsOfKind(CodePropertyKind.PathSegment, CodePropertyKind.CurrentPath)) + currentProperty.Type.IsNullable = true; } private static void CorrectMethodType(CodeMethod currentMethod) { if(currentMethod.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator)) { @@ -126,7 +135,12 @@ private static void CorrectMethodType(CodeMethod currentMethod) { currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Options)).ToList().ForEach(x => x.Type.Name = "Collection"); } else if(currentMethod.IsOfKind(CodeMethodKind.Serializer)) - currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Serializer) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]); + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Serializer)).ToList().ForEach(x => { + x.Optional = false; + x.Type.IsNullable = true; + if(x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)) + x.Type.Name = x.Type.Name[1..]; + }); else if(currentMethod.IsOfKind(CodeMethodKind.Deserializer)) { currentMethod.ReturnType.Name = $"Map>"; currentMethod.Name = "getFieldDeserializers"; diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index 98ced19b0e..bbb3d5a8d5 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -9,7 +9,7 @@ public class RubyRefiner : CommonLanguageRefiner, ILanguageRefiner public RubyRefiner(GenerationConfiguration configuration) : base(configuration) {} public override void Refine(CodeNamespace generatedCode) { - ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, "_by_id"); + ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, false, "_by_id"); AddPropertiesAndMethodTypesImports(generatedCode, false, false, false); AddParsableInheritanceForModelClasses(generatedCode); AddInheritedAndMethodTypesImports(generatedCode); diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index a9af7f4dad..e43ef616f5 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -9,7 +9,7 @@ public override void Refine(CodeNamespace generatedCode) { PatchResponseHandlerType(generatedCode); AddDefaultImports(generatedCode, Array.Empty>(), defaultNamespacesForModels, defaultNamespacesForRequestBuilders); - ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, "ById"); + ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, false, "ById"); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType); CorrectCoreTypesForBackingStore(generatedCode, "@microsoft/kiota-abstractions", "BackingStoreFactorySingleton.instance.createBackingStore()"); FixReferencesToEntityType(generatedCode); diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index bd8e94f146..a26fdf1da0 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -109,6 +109,7 @@ private static void WriteConstructorBody(CodeClass parentClass, CodeMethod curre if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.HttpCore, CodePropertyKind.HttpCore, writer); AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.CurrentPath, CodePropertyKind.CurrentPath, writer); + AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RawUrl, CodePropertyKind.RawUrl, writer); } } private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMethod currentMethod, CodeParameterKind parameterKind, CodePropertyKind propertyKind, LanguageWriter writer) { @@ -214,7 +215,7 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, CodeParameter req writer.WriteLine($"final RequestInfo {requestInfoVarName} = new RequestInfo() {{{{"); writer.IncreaseIndent(); - writer.WriteLines($"uri = new URI({conventions.CurrentPathPropertyName} + {conventions.PathSegmentPropertyName});", + writer.WriteLines($"this.setUri({conventions.CurrentPathPropertyName}, {conventions.PathSegmentPropertyName}, {conventions.RawUrlPropertyName});", $"httpMethod = HttpMethod.{codeElement.HttpMethod?.ToString().ToUpperInvariant()};"); writer.DecreaseIndent(); writer.WriteLine("}};"); @@ -259,6 +260,7 @@ private void WriteSerializerBody(CodeClass parentClass, LanguageWriter writer) { if(additionalDataProperty != null) writer.WriteLine($"writer.writeAdditionalData(this.get{additionalDataProperty.Name.ToFirstCharacterUpperCase()}());"); } + private static CodeParameterOrderComparer parameterOrderComparer = new CodeParameterOrderComparer(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string returnType) { var accessModifier = conventions.GetAccessModifier(code.Access); var genericTypeParameterDeclaration = code.IsOfKind(CodeMethodKind.Deserializer) ? " ": string.Empty; @@ -271,7 +273,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string (CodeMethodKind.Setter) => $"set{code.AccessedProperty?.Name?.ToFirstCharacterUpperCase()}", _ => code.Name.ToFirstCharacterLowerCase() }); - var parameters = string.Join(", ", code.Parameters.Select(p=> conventions.GetParameterSignature(p)).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p=> conventions.GetParameterSignature(p)).ToList()); var throwableDeclarations = code.IsOfKind(CodeMethodKind.RequestGenerator) ? "throws URISyntaxException ": string.Empty; var collectionCorrectedReturnType = code.ReturnType.IsArray && code.IsOfKind(CodeMethodKind.RequestExecutor) ? $"Iterable<{returnType.StripArraySuffix()}>" : @@ -298,7 +300,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { } private string GetDeserializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType.Name, propType.IsNullable); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -323,7 +325,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType) { } private string GetSerializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType.Name, propType.IsNullable); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) diff --git a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs index 504a557b39..763b60c5c1 100644 --- a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs +++ b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs @@ -13,6 +13,7 @@ public class JavaConventionService : ILanguageConventionService public string PathSegmentPropertyName => "pathSegment"; public string CurrentPathPropertyName => "currentPath"; public string HttpCorePropertyName => "httpCore"; + public string RawUrlPropertyName => "isRawUrl"; internal HashSet PrimitiveTypes = new() {"String", "Boolean", "Integer", "Float", "Long", "Guid", "OffsetDateTime", _voidTypeName, _streamTypeName }; public string ParseNodeInterfaceName => "ParseNode"; internal string DocCommentStart = "/**"; @@ -28,7 +29,8 @@ public string GetAccessModifier(AccessModifier access) public string GetParameterSignature(CodeParameter parameter) { - return $"@javax.annotation.{(parameter.Optional ? "Nullable" : "Nonnull")} final {GetTypeString(parameter.Type)} {parameter.Name}"; + var nullAnnotation = parameter.Type.IsNullable ? $"@javax.annotation.{(parameter.Optional ? "Nullable" : "Nonnull")} " : string.Empty; + return $"{nullAnnotation}final {GetTypeString(parameter.Type)} {parameter.Name}"; } public string GetTypeString(CodeTypeBase code) @@ -36,7 +38,7 @@ public string GetTypeString(CodeTypeBase code) if(code is CodeUnionType) throw new InvalidOperationException($"Java does not support union types, the union type {code.Name} should have been filtered out by the refiner"); else if (code is CodeType currentType) { - var typeName = TranslateType(currentType.Name); + var typeName = TranslateType(currentType.Name, currentType.IsNullable); var collectionPrefix = currentType.CollectionKind == CodeType.CodeTypeCollectionKind.Complex ? "List<" : string.Empty; var collectionSuffix = currentType.CollectionKind switch { CodeType.CodeTypeCollectionKind.Complex => ">", @@ -50,11 +52,13 @@ public string GetTypeString(CodeTypeBase code) } else throw new InvalidOperationException($"type of type {code.GetType()} is unknown"); } - - public string TranslateType(string typeName) + public string TranslateType(string typeName){ + return TranslateType(typeName, false); + } + public string TranslateType(string typeName, bool isNullable) { return (typeName) switch {//TODO we're probably missing a bunch of type mappings - ("void") => typeName.ToFirstCharacterLowerCase(), //little casing hack + ("void" or "boolean") when !isNullable => typeName.ToFirstCharacterLowerCase(), //little casing hack _ => typeName.ToFirstCharacterUpperCase() ?? "Object", }; } @@ -68,7 +72,7 @@ public void WriteShortDescription(string description, LanguageWriter writer) internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, LanguageWriter writer, string suffix = default) { // because if currentPath is null it'll add "null" to the string... var currentPath = addCurrentPath ? $"{CurrentPathPropertyName} + " : string.Empty; - writer.WriteLines($"return new {returnType}({currentPath}{PathSegmentPropertyName}{suffix}, {HttpCorePropertyName});"); + writer.WriteLines($"return new {returnType}({currentPath}{PathSegmentPropertyName}{suffix}, {HttpCorePropertyName}, false);"); } } } From caff9a907937c7a2ceb8fd5669357ab6b75e452e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 13:50:47 -0400 Subject: [PATCH 09/23] - fixes a bug in java abstractions where URL parsing would not work as expected --- .../main/java/com/microsoft/kiota/RequestInfo.java | 2 +- .../java/com/microsoft/kiota/RequestInfoTest.java | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java index 6c3b6619ab..81d1657ca5 100644 --- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java +++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/RequestInfo.java @@ -33,7 +33,7 @@ public void setUri(@Nullable final String currentPath, @Nullable final String pa if(currentPath == null || currentPath.isEmpty()) { throw new IllegalArgumentException("currentPath cannot be null or empty"); } - final var questionMarkSplat = currentPath.split("?"); + final var questionMarkSplat = currentPath.split("\\?"); final var schemeHostAndPath = questionMarkSplat[0]; this.setUriFromString(schemeHostAndPath); if (questionMarkSplat.length > 1) { diff --git a/abstractions/java/lib/src/test/java/com/microsoft/kiota/RequestInfoTest.java b/abstractions/java/lib/src/test/java/com/microsoft/kiota/RequestInfoTest.java index 067180f836..45822406ee 100644 --- a/abstractions/java/lib/src/test/java/com/microsoft/kiota/RequestInfoTest.java +++ b/abstractions/java/lib/src/test/java/com/microsoft/kiota/RequestInfoTest.java @@ -7,8 +7,14 @@ import static org.junit.jupiter.api.Assertions.*; class RequestInfoTest { - @Test void testSomeLibraryMethod() { - RequestInfoTest classUnderTest = new RequestInfoTest(); - assertNotNull(classUnderTest); + @Test + void setsRawUri() { + final var requestInfo = new RequestInfo(); + requestInfo.setUri("https://graph.microsoft.com/test", null, true); + assertEquals("https://graph.microsoft.com/test", requestInfo.uri.toString()); + + requestInfo.setUri("https://graph.microsoft.com/test?qp=one", null, true); + assertEquals("https://graph.microsoft.com/test", requestInfo.uri.toString()); + assertEquals("one", requestInfo.queryParameters.get("qp")); } } From 9e1a0e194c6a6cf80447c1b60acb03b6e03632f6 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 13:51:43 -0400 Subject: [PATCH 10/23] - adds constructor overload in java for default parameter --- src/Kiota.Builder/CodeDOM/CodeBlock.cs | 2 +- src/Kiota.Builder/CodeDOM/CodeTypeBase.cs | 2 +- src/Kiota.Builder/Refiners/JavaRefiner.cs | 32 +++++++++++++------ .../Writers/Java/CodeMethodWriter.cs | 17 ++++++++-- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/CodeDOM/CodeBlock.cs b/src/Kiota.Builder/CodeDOM/CodeBlock.cs index 463e61feb1..17589d8f12 100644 --- a/src/Kiota.Builder/CodeDOM/CodeBlock.cs +++ b/src/Kiota.Builder/CodeDOM/CodeBlock.cs @@ -66,7 +66,7 @@ returnedValue is CodeProperty cProp && // indexer retrofited to method in the parent request builder on the path and conflicting with the collection request builder propeerty returnedValue = innerChildElements.GetOrAdd($"{element.Name}-indexerbackcompat", element); added = true; - } else if(currentMethod.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator)) { + } else if(currentMethod.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator, CodeMethodKind.Constructor)) { // allows for methods overload var methodOverloadNameSuffix = currentMethod.Parameters.Any() ? currentMethod.Parameters.Select(x => x.Name).OrderBy(x => x).Aggregate((x, y) => x + y) : "1"; returnedValue = innerChildElements.GetOrAdd($"{element.Name}-{methodOverloadNameSuffix}", element); diff --git a/src/Kiota.Builder/CodeDOM/CodeTypeBase.cs b/src/Kiota.Builder/CodeDOM/CodeTypeBase.cs index ab101d7277..de677ef75e 100644 --- a/src/Kiota.Builder/CodeDOM/CodeTypeBase.cs +++ b/src/Kiota.Builder/CodeDOM/CodeTypeBase.cs @@ -17,7 +17,7 @@ protected CodeTypeBase(CodeElement parent) : base(parent) { public CodeTypeCollectionKind CollectionKind {get;set;} = CodeTypeCollectionKind.None; public bool IsCollection { get { return CollectionKind != CodeTypeCollectionKind.None; } } public bool IsArray { get { return CollectionKind == CodeTypeCollectionKind.Array; } } - public ChildType BaseClone(CodeTypeBase source) where ChildType : CodeTypeBase + protected ChildType BaseClone(CodeTypeBase source) where ChildType : CodeTypeBase { ActionOf = source.ActionOf; IsNullable = source.IsNullable; diff --git a/src/Kiota.Builder/Refiners/JavaRefiner.cs b/src/Kiota.Builder/Refiners/JavaRefiner.cs index d3c1c6c9da..6a7a88310f 100644 --- a/src/Kiota.Builder/Refiners/JavaRefiner.cs +++ b/src/Kiota.Builder/Refiners/JavaRefiner.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Kiota.Builder.Extensions; @@ -10,7 +11,7 @@ public JavaRefiner(GenerationConfiguration configuration) : base(configuration) public override void Refine(CodeNamespace generatedCode) { AddInnerClasses(generatedCode, false); - AndInsertOverrideMethodForRequestExecutorsAndBuilders(generatedCode); + InsertOverrideMethodForRequestExecutorsAndBuildersAndConstructors(generatedCode); ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, true); ConvertUnionTypesToWrapper(generatedCode); AddRequireNonNullImports(generatedCode); @@ -29,7 +30,7 @@ public override void Refine(CodeNamespace generatedCode) CodePropertyKind.AdditionalData, CodePropertyKind.BackingStore, }, _configuration.UsesBackingStore, true); - SetParametersToNullable(generatedCode, new Tuple(CodeMethodKind.Setter, CodePropertyKind.AdditionalData)); + SetSetterParametersToNullable(generatedCode, new Tuple(CodeMethodKind.Setter, CodePropertyKind.AdditionalData)); AddConstructorsForDefaultValues(generatedCode, true); CorrectCoreTypesForBackingStore(generatedCode, "com.microsoft.kiota.store", "BackingStoreFactorySingleton.instance.createBackingStore()"); ReplaceDefaultSerializationModules(generatedCode, "com.microsoft.kiota.serialization.JsonSerializationWriterFactory"); @@ -39,11 +40,11 @@ public override void Refine(CodeNamespace generatedCode) "com.microsoft.kiota.serialization.SerializationWriterFactoryRegistry" }, new [] { "com.microsoft.kiota.serialization.ParseNodeFactoryRegistry" }); } - private static void SetParametersToNullable(CodeElement currentElement, params Tuple[] accessorPairs) { + private static void SetSetterParametersToNullable(CodeElement currentElement, params Tuple[] accessorPairs) { if(currentElement is CodeMethod method && accessorPairs.Any(x => method.IsOfKind(x.Item1) && (method.AccessedProperty?.IsOfKind(x.Item2) ?? false))) method.Parameters.ForEach(x => x.Type.IsNullable = true); - CrawlTree(currentElement, element => SetParametersToNullable(element, accessorPairs)); + CrawlTree(currentElement, element => SetSetterParametersToNullable(element, accessorPairs)); } private static void AddEnumSetImport(CodeElement currentElement) { if(currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model) && @@ -150,6 +151,10 @@ private static void CorrectMethodType(CodeMethod currentMethod) { .Where(x => x.Type.Name.StartsWith("I", StringComparison.OrdinalIgnoreCase)) .ToList() .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" + else if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore, CodeParameterKind.CurrentPath)).ToList().ForEach(x => x.Type.IsNullable = true); + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I"); + } } private static void AddRequireNonNullImports(CodeElement currentElement) { if(currentElement is CodeMethod currentMethod && currentMethod.Parameters.Any(x => !x.Optional)) { @@ -165,7 +170,7 @@ private static void AddRequireNonNullImports(CodeElement currentElement) { } CrawlTree(currentElement, AddRequireNonNullImports); } - private static void AndInsertOverrideMethodForRequestExecutorsAndBuilders(CodeElement currentElement) { + private static void InsertOverrideMethodForRequestExecutorsAndBuildersAndConstructors(CodeElement currentElement) { if(currentElement is CodeClass currentClass) { var codeMethods = currentClass.GetChildElements(true).OfType(); if(codeMethods.Any()) { @@ -187,17 +192,24 @@ private static void AndInsertOverrideMethodForRequestExecutorsAndBuilders(CodeEl .Union(originalGeneratorMethods .Select(x => GetMethodClone(x, CodeParameterKind.QueryParameter, CodeParameterKind.Headers, CodeParameterKind.Options))) .Where(x => x != null); - if(executorMethodsToAdd.Any() || generatorMethodsToAdd.Any()) - currentClass.AddMethod(executorMethodsToAdd.Union(generatorMethodsToAdd).ToArray()); + var originalConstructors = codeMethods.Where(x => x.IsOfKind(CodeMethodKind.Constructor)); + var constructorsToAdd = originalConstructors + .Select(x => GetMethodClone(x, CodeParameterKind.RawUrl)) + .Where(x => x != null); + if(executorMethodsToAdd.Any() || generatorMethodsToAdd.Any() || constructorsToAdd.Any()) + currentClass.AddMethod(executorMethodsToAdd + .Union(generatorMethodsToAdd) + .Union(constructorsToAdd) + .ToArray()); } } - CrawlTree(currentElement, AndInsertOverrideMethodForRequestExecutorsAndBuilders); + CrawlTree(currentElement, InsertOverrideMethodForRequestExecutorsAndBuildersAndConstructors); } private static CodeMethod GetMethodClone(CodeMethod currentMethod, params CodeParameterKind[] parameterTypesToExclude) { - if(currentMethod.Parameters.Any(x => parameterTypesToExclude.Contains(x.ParameterKind))) { + if(currentMethod.Parameters.Any(x => x.IsOfKind(parameterTypesToExclude))) { var cloneMethod = currentMethod.Clone() as CodeMethod; - cloneMethod.Parameters.RemoveAll(x => parameterTypesToExclude.Contains(x.ParameterKind)); + cloneMethod.Parameters.RemoveAll(x => x.IsOfKind(parameterTypesToExclude)); cloneMethod.OriginalMethod = currentMethod; return cloneMethod; } diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index a26fdf1da0..e9c51c8b4b 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -31,9 +31,10 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri var queryStringParam = codeElement.Parameters.OfKind(CodeParameterKind.QueryParameter); var headersParam = codeElement.Parameters.OfKind(CodeParameterKind.Headers); var optionsParam = codeElement.Parameters.OfKind(CodeParameterKind.Options); - foreach(var parameter in codeElement.Parameters.Where(x => !x.Optional).OrderBy(x => x.Name)) { - writer.WriteLine($"Objects.requireNonNull({parameter.Name});"); - } + if(!codeElement.IsOverload) + foreach(var parameter in codeElement.Parameters.Where(x => !x.Optional).OrderBy(x => x.Name)) { + writer.WriteLine($"Objects.requireNonNull({parameter.Name});"); + } switch(codeElement.MethodKind) { case CodeMethodKind.Serializer: WriteSerializerBody(parentClass, writer); @@ -63,6 +64,9 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri WriteConstructorBody(parentClass, codeElement, writer, inherits); WriteApiConstructorBody(parentClass, codeElement, writer); break; + case CodeMethodKind.Constructor when codeElement.IsOverload && parentClass.IsOfKind(CodeClassKind.RequestBuilder): + WriteRequestBuilderConstructorCall(parentClass, codeElement, writer); + break; case CodeMethodKind.Constructor: WriteConstructorBody(parentClass, codeElement, writer, inherits); break; @@ -75,6 +79,13 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri writer.DecreaseIndent(); writer.WriteLine("}"); } + private void WriteRequestBuilderConstructorCall(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + { + var httpCoreParameter = codeElement.Parameters.OfKind(CodeParameterKind.HttpCore); + var currentPathParameter = codeElement.Parameters.OfKind(CodeParameterKind.CurrentPath); + var originalRawUrlParameter = codeElement.OriginalMethod.Parameters.OfKind(CodeParameterKind.RawUrl); + writer.WriteLine($"this({currentPathParameter.Name}, {httpCoreParameter.Name}, {originalRawUrlParameter.DefaultValue});"); + } private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) { var httpCoreProperty = parentClass.GetChildElements(true).OfType().FirstOrDefault(x => x.IsOfKind(CodePropertyKind.HttpCore)); var httpCoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.HttpCore)); From d896a92d2ea68d404e5cde0cbe992e9bdc8b0011 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 14:20:50 -0400 Subject: [PATCH 11/23] - adds set uri method to go abstractions --- abstractions/go/request_info.go | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/abstractions/go/request_info.go b/abstractions/go/request_info.go index aff21e08ad..7741137e84 100644 --- a/abstractions/go/request_info.go +++ b/abstractions/go/request_info.go @@ -3,7 +3,9 @@ package abstractions import ( "errors" "reflect" + "strings" + "net/url" u "net/url" s "github.com/microsoft/kiota/abstractions/go/serialization" @@ -19,6 +21,48 @@ type RequestInfo struct { options map[string]MiddlewareOption } +func NewRequestInfo() *RequestInfo { + return &RequestInfo{ + URI: u.URL{}, + Headers: make(map[string]string), + QueryParameters: make(map[string]string), + options: make(map[string]MiddlewareOption), + } +} + +func (request *RequestInfo) SetUri(currentPath string, pathSegment string, isRawUrl bool) error { + if isRawUrl { + if currentPath == "" { + return errors.New("current path cannot be empty") + } + questionMarkSplat := strings.Split(currentPath, "?") + schemeHostAndPath := questionMarkSplat[0] + uri, err := url.Parse(schemeHostAndPath) + if err != nil { + return err + } + request.URI = *uri + if len(questionMarkSplat) > 1 { + queryParameters := questionMarkSplat[1] + for _, queryParameter := range strings.Split(queryParameters, "&") { + keyValue := strings.Split(queryParameter, "=") + if len(keyValue) == 2 { + request.QueryParameters[keyValue[0]] = keyValue[1] + } else if len(keyValue) == 1 { + request.QueryParameters[keyValue[0]] = "" + } + } + } + } else { + uri, err := url.Parse(currentPath + pathSegment) + if err != nil { + return err + } + request.URI = *uri + } + return nil +} + func (request *RequestInfo) AddMiddlewareOptions(options ...MiddlewareOption) error { if options == nil { return errors.New("MiddlewareOptions cannot be nil") From 2cc60d11d3fae5cfe7ab34559e762ab15ed7b103 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 14:34:59 -0400 Subject: [PATCH 12/23] - adds support for raw URLs in go --- src/Kiota.Builder/Refiners/GoRefiner.cs | 1 - src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs | 9 +++++---- src/Kiota.Builder/Writers/Go/GoConventionService.cs | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index 023cb6a1da..ab921dbe5f 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -98,7 +98,6 @@ private static void AddErrorImportForEnums(CodeElement currentElement) { new ("MiddlewareOption", "github.com/microsoft/kiota/abstractions/go"), new ("QueryParametersBase", "github.com/microsoft/kiota/abstractions/go"), new ("Parsable", "github.com/microsoft/kiota/abstractions/go/serialization"), - new ("*url", "net/url"), }; private static readonly Tuple[] defaultNamespaces = new Tuple[] { new ("SerializationWriter", "github.com/microsoft/kiota/abstractions/go/serialization"), diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs index 0416c126a0..646d3c663f 100644 --- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs @@ -94,6 +94,7 @@ private void WriteSerializerBody(CodeClass parentClass, LanguageWriter writer) { writer.WriteLine("return nil"); } private static string errorVarDeclaration(bool shouldDeclareErrorVar) => shouldDeclareErrorVar ? ":" : string.Empty; + private static CodeParameterOrderComparer parameterOrderComparer = new CodeParameterOrderComparer(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string returnType, CodeClass parentClass) { var returnTypeAsyncPrefix = code.IsAsync ? "func() (" : string.Empty; var returnTypeAsyncSuffix = code.IsAsync ? "error)" : string.Empty; @@ -107,7 +108,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string _ when code.Access == AccessModifier.Public => code.Name.ToFirstCharacterUpperCase(), _ => code.Name.ToFirstCharacterLowerCase() }); - var parameters = string.Join(", ", code.Parameters.Select(p => conventions.GetParameterSignature(p, parentClass)).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p => conventions.GetParameterSignature(p, parentClass)).ToList()); var classType = conventions.GetTypeString(new CodeType(parentClass) { Name = parentClass.Name, TypeDefinition = parentClass }, parentClass); var associatedTypePrefix = isConstructor ? string.Empty : $" (m {classType})"; var finalReturnType = isConstructor ? classType : $"{returnTypeAsyncPrefix}{returnType}{returnTypeAsyncSuffix}"; @@ -189,6 +190,7 @@ private static void WriteConstructorBody(CodeClass parentClass, CodeMethod curre if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.HttpCore, CodePropertyKind.HttpCore, writer); AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.CurrentPath, CodePropertyKind.CurrentPath, writer); + AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RawUrl, CodePropertyKind.RawUrl, writer); } } private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMethod currentMethod, CodeParameterKind parameterKind, CodePropertyKind propertyKind, LanguageWriter writer) { @@ -320,9 +322,8 @@ private static void WriteGeneratorMethodCall(CodeMethod codeElement, CodeParamet private void WriteRequestGeneratorBody(CodeMethod codeElement, CodeParameter requestBodyParam, CodeParameter queryStringParam, CodeParameter headersParam, CodeParameter optionsParam, LanguageWriter writer, CodeClass parentClass, string returnType) { if(codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null"); - writer.WriteLine($"{rInfoVarName} := new({conventions.AbstractionsHash}.RequestInfo)"); - writer.WriteLines($"uri, err := url.Parse(m.{conventions.CurrentPathPropertyName} + m.{conventions.PathSegmentPropertyName})", - $"{rInfoVarName}.URI = *uri", + writer.WriteLine($"{rInfoVarName} := {conventions.AbstractionsHash}.NewRequestInfo()"); + writer.WriteLines($"err := {rInfoVarName}.SetUri(m.{conventions.CurrentPathPropertyName}, m.{conventions.PathSegmentPropertyName}, m.{conventions.RawUrlPropertyName})", $"{rInfoVarName}.Method = {conventions.AbstractionsHash}.{codeElement.HttpMethod?.ToString().ToUpperInvariant()}"); WriteReturnError(writer, returnType); if(requestBodyParam != null) diff --git a/src/Kiota.Builder/Writers/Go/GoConventionService.cs b/src/Kiota.Builder/Writers/Go/GoConventionService.cs index 20f8ac9a53..7cd44a944b 100644 --- a/src/Kiota.Builder/Writers/Go/GoConventionService.cs +++ b/src/Kiota.Builder/Writers/Go/GoConventionService.cs @@ -18,6 +18,7 @@ public class GoConventionService : ILanguageConventionService public string HttpCorePropertyName => "httpCore"; public string ParseNodeInterfaceName => "ParseNode"; + public string RawUrlPropertyName => "isRawUrl"; public object AbstractionsHash => "ida96af0f171bb75f894a4013a6b3146a4397c58f11adb81a2b7cbea9314783a9"; public string GetAccessModifier(AccessModifier access) @@ -125,7 +126,7 @@ internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, Lang var splatImport = returnType.Split('.'); var constructorName = splatImport.Last().ToFirstCharacterUpperCase(); var moduleName = returnType.Length > 1 ? splatImport.First() + "." : string.Empty; - writer.WriteLines($"return *{moduleName}New{constructorName}({currentPath}m.{PathSegmentPropertyName}{suffix}, m.{HttpCorePropertyName});"); + writer.WriteLines($"return *{moduleName}New{constructorName}({currentPath}m.{PathSegmentPropertyName}{suffix}, m.{HttpCorePropertyName}, false);"); } } } From 7bdb2c32b7762982b53062c59ed2ee0a99a69973 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 15:11:33 -0400 Subject: [PATCH 13/23] - code-linting --- src/Kiota.Builder/Refiners/JavaRefiner.cs | 2 +- .../Writers/CSharp/CSharpConventionService.cs | 34 ++++++------ .../Writers/CSharp/CodeMethodWriter.cs | 4 +- .../CommonLanguageConventionService.cs | 55 +++++++++++++++++++ .../Writers/Go/CodeMethodWriter.cs | 4 +- .../Writers/Go/GoConventionService.cs | 38 ++++++------- .../Writers/ILanguageConventionService.cs | 3 +- .../Writers/Java/CodeMethodWriter.cs | 18 +++--- .../Writers/Java/JavaConventionService.cs | 44 +++++++-------- .../Writers/Ruby/CodeMethodWriter.cs | 4 +- .../Writers/Ruby/RubyConventionService.cs | 35 ++++++------ .../Writers/TypeScript/CodeMethodWriter.cs | 4 +- .../TypeScript/TypeScriptConventionService.cs | 36 ++++++------ 13 files changed, 168 insertions(+), 113 deletions(-) create mode 100644 src/Kiota.Builder/Writers/CommonLanguageConventionService.cs diff --git a/src/Kiota.Builder/Refiners/JavaRefiner.cs b/src/Kiota.Builder/Refiners/JavaRefiner.cs index 6a7a88310f..1431cf2aec 100644 --- a/src/Kiota.Builder/Refiners/JavaRefiner.cs +++ b/src/Kiota.Builder/Refiners/JavaRefiner.cs @@ -153,7 +153,7 @@ private static void CorrectMethodType(CodeMethod currentMethod) { .ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" else if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore, CodeParameterKind.CurrentPath)).ToList().ForEach(x => x.Type.IsNullable = true); - currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I"); + currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I" } } private static void AddRequireNonNullImports(CodeElement currentElement) { diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index d5dde5b8db..a9f540d5ac 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -4,22 +4,22 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.CSharp { - public class CSharpConventionService : ILanguageConventionService { - public string StreamTypeName => "stream"; - public string VoidTypeName => "void"; - public string DocCommentPrefix => "/// "; - public string PathSegmentPropertyName => "PathSegment"; - public string CurrentPathPropertyName => "CurrentPath"; - public string HttpCorePropertyName => "HttpCore"; + public class CSharpConventionService : CommonLanguageConventionService { + public override string StreamTypeName => "stream"; + public override string VoidTypeName => "void"; + public override string DocCommentPrefix => "/// "; + public override string PathSegmentPropertyName => "PathSegment"; + public override string CurrentPathPropertyName => "CurrentPath"; + public override string HttpCorePropertyName => "HttpCore"; public HashSet NullableTypes { get; } = new() { "int", "bool", "float", "double", "decimal", "Guid", "DateTimeOffset" }; public static string NullableMarker => "?"; - public string ParseNodeInterfaceName => "IParseNode"; - public string RawUrlPropertyName => "IsRawUrl"; - public void WriteShortDescription(string description, LanguageWriter writer) { + public override string ParseNodeInterfaceName => "IParseNode"; + public override string RawUrlPropertyName => "IsRawUrl"; + public override void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) writer.WriteLine($"{DocCommentPrefix}{description}"); } - public string GetAccessModifier(AccessModifier access) + public override string GetAccessModifier(AccessModifier access) { return (access) switch { (AccessModifier.Public) => "public", @@ -34,12 +34,12 @@ internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, Lang internal bool ShouldTypeHaveNullableMarker(CodeTypeBase propType, string propTypeName) { return propType.IsNullable && (NullableTypes.Contains(propTypeName) || (propType is CodeType codeType && codeType.TypeDefinition is CodeEnum)); } - public string GetTypeString(CodeTypeBase code) + public override string GetTypeString(CodeTypeBase code) { if(code is CodeUnionType) throw new InvalidOperationException($"CSharp does not support union types, the union type {code.Name} should have been filtered out by the refiner"); else if (code is CodeType currentType) { - var typeName = TranslateType(currentType.Name); + var typeName = TranslateType(currentType); var nullableSuffix = ShouldTypeHaveNullableMarker(code, typeName) ? NullableMarker : string.Empty; var collectionPrefix = currentType.CollectionKind == CodeType.CodeTypeCollectionKind.Complex ? "List<" : string.Empty; var collectionSuffix = currentType.CollectionKind switch { @@ -55,16 +55,16 @@ public string GetTypeString(CodeTypeBase code) else throw new InvalidOperationException($"type of type {code.GetType()} is unknown"); } - public string TranslateType(string typeName) + public override string TranslateType(CodeType type) { - switch (typeName) + switch (type.Name) { case "integer": return "int"; case "boolean": return "bool"; case "string": return "string"; // little casing hack case "object": return "object"; case "void": return "void"; - default: return typeName?.ToFirstCharacterUpperCase() ?? "object"; + default: return type.Name?.ToFirstCharacterUpperCase() ?? "object"; } } public bool IsPrimitiveType(string typeName) { @@ -72,7 +72,7 @@ public bool IsPrimitiveType(string typeName) { (NullableTypes.Contains(typeName) || "string".Equals(typeName, StringComparison.OrdinalIgnoreCase)); } - public string GetParameterSignature(CodeParameter parameter) + public override string GetParameterSignature(CodeParameter parameter) { var parameterType = GetTypeString(parameter.Type); var defaultValue = (parameter) switch { diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs index 4dafc42e2e..2c12772005 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -118,7 +118,7 @@ private void WriteDeserializerBody(CodeMethod codeElement, CodeClass parentClass } private string GetDeserializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -242,7 +242,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string } private string GetSerializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType); var nullableSuffix = conventions.ShouldTypeHaveNullableMarker(propType, propertyType) ? CSharpConventionService.NullableMarker : string.Empty; if(propType is CodeType currentType) { if(isCollection) diff --git a/src/Kiota.Builder/Writers/CommonLanguageConventionService.cs b/src/Kiota.Builder/Writers/CommonLanguageConventionService.cs new file mode 100644 index 0000000000..42f7f201e6 --- /dev/null +++ b/src/Kiota.Builder/Writers/CommonLanguageConventionService.cs @@ -0,0 +1,55 @@ +using System; +using System.Linq; + +namespace Kiota.Builder.Writers { + public abstract class CommonLanguageConventionService : ILanguageConventionService { + public abstract string StreamTypeName + { + get; + } + public abstract string VoidTypeName + { + get; + } + public abstract string DocCommentPrefix + { + get; + } + public abstract string PathSegmentPropertyName + { + get; + } + public abstract string CurrentPathPropertyName + { + get; + } + public abstract string HttpCorePropertyName + { + get; + } + public abstract string RawUrlPropertyName + { + get; + } + public abstract string ParseNodeInterfaceName + { + get; + } + + public abstract string GetAccessModifier(AccessModifier access); + public abstract string GetParameterSignature(CodeParameter parameter); + public abstract string GetTypeString(CodeTypeBase code); + + public string TranslateType(CodeTypeBase type) { + if(type is CodeType currentType) + return TranslateType(currentType); + else if(type is CodeUnionType currentUnionType) + return TranslateType(currentUnionType.AllTypes.First()); + else + throw new InvalidOperationException("Unknown type"); + } + + public abstract string TranslateType(CodeType type); + public abstract void WriteShortDescription(string description, LanguageWriter writer); + } +} diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs index 646d3c663f..343b058e73 100644 --- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs @@ -389,7 +389,7 @@ private static void WriteAsyncReturnError(LanguageWriter writer, params string[] } private string GetDeserializationMethodName(CodeTypeBase propType, CodeClass parentClass) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyTypeName = conventions.TranslateType(propType.AllTypes.First().Name); + var propertyTypeName = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -420,7 +420,7 @@ private string GetTypeFactory(CodeTypeBase propTypeBase, CodeClass parentClass, private void WriteSerializationMethodCall(CodeTypeBase propType, CodeClass parentClass, string serializationKey, string valueGet, bool shouldDeclareErrorVar, LanguageWriter writer) { serializationKey = $"\"{serializationKey}\""; var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType); var errorPrefix = $"err {errorVarDeclaration(shouldDeclareErrorVar)}= writer."; if(propType is CodeType currentType) { if(isCollection) { diff --git a/src/Kiota.Builder/Writers/Go/GoConventionService.cs b/src/Kiota.Builder/Writers/Go/GoConventionService.cs index 7cd44a944b..8e44643ada 100644 --- a/src/Kiota.Builder/Writers/Go/GoConventionService.cs +++ b/src/Kiota.Builder/Writers/Go/GoConventionService.cs @@ -3,36 +3,36 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Go { - public class GoConventionService : ILanguageConventionService + public class GoConventionService : CommonLanguageConventionService { - public string StreamTypeName => "[]byte"; + public override string StreamTypeName => "[]byte"; - public string VoidTypeName => string.Empty; + public override string VoidTypeName => string.Empty; - public string DocCommentPrefix => string.Empty; + public override string DocCommentPrefix => string.Empty; - public string PathSegmentPropertyName => "pathSegment"; + public override string PathSegmentPropertyName => "pathSegment"; - public string CurrentPathPropertyName => "currentPath"; + public override string CurrentPathPropertyName => "currentPath"; - public string HttpCorePropertyName => "httpCore"; + public override string HttpCorePropertyName => "httpCore"; - public string ParseNodeInterfaceName => "ParseNode"; - public string RawUrlPropertyName => "isRawUrl"; + public override string ParseNodeInterfaceName => "ParseNode"; + public override string RawUrlPropertyName => "isRawUrl"; public object AbstractionsHash => "ida96af0f171bb75f894a4013a6b3146a4397c58f11adb81a2b7cbea9314783a9"; - public string GetAccessModifier(AccessModifier access) + public override string GetAccessModifier(AccessModifier access) { throw new InvalidOperationException("go uses a naming convention for access modifiers"); } - public string GetParameterSignature(CodeParameter parameter) { + public override string GetParameterSignature(CodeParameter parameter) { throw new InvalidOperationException("go needs import symbols, use the local override instead"); } public string GetParameterSignature(CodeParameter parameter, CodeElement targetElement) { return $"{parameter.Name} {GetTypeString(parameter.Type, targetElement)}"; } - public string GetTypeString(CodeTypeBase code) => throw new InvalidOperationException("go needs import symbols, use the local override instead"); + public override string GetTypeString(CodeTypeBase code) => throw new InvalidOperationException("go needs import symbols, use the local override instead"); public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool addPointerSymbol = true, bool addCollectionSymbol = true) { if(code is CodeUnionType) @@ -41,7 +41,7 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool a var importSymbol = GetImportSymbol(code, targetElement); if(!string.IsNullOrEmpty(importSymbol)) importSymbol += "."; - var typeName = TranslateType(currentType.Name); + var typeName = TranslateType(currentType); var nullableSymbol = addPointerSymbol && currentType.IsNullable && currentType.CollectionKind == CodeTypeBase.CodeTypeCollectionKind.None && @@ -59,11 +59,11 @@ public string GetTypeString(CodeTypeBase code, CodeElement targetElement, bool a else throw new InvalidOperationException($"type of type {code.GetType()} is unknown"); } - public string TranslateType(string typeName) + public override string TranslateType(CodeType type) { - if(typeName.StartsWith("map[")) return typeName; //casing hack + if(type.Name.StartsWith("map[")) return type.Name; //casing hack - return (typeName) switch { + return (type.Name) switch { "void" => string.Empty, "string" => "string", "float" => "float32", @@ -74,8 +74,8 @@ public string TranslateType(string typeName) "guid" => "uuid.UUID", "datetimeoffset" => "time.Time", "binary" => "[]byte", - ("String") => TranslateType(typeName.ToFirstCharacterLowerCase()), //casing hack - _ => typeName.ToFirstCharacterUpperCase() ?? "Object", + ("String") => type.Name.ToFirstCharacterLowerCase(), //casing hack + _ => type.Name.ToFirstCharacterUpperCase() ?? "Object", }; } private static bool IsPrimitiveType(string typeName) { @@ -115,7 +115,7 @@ targetElement is CodeClass targetClass && return string.Empty; } - public void WriteShortDescription(string description, LanguageWriter writer) + public override void WriteShortDescription(string description, LanguageWriter writer) { throw new NotImplementedException(); } diff --git a/src/Kiota.Builder/Writers/ILanguageConventionService.cs b/src/Kiota.Builder/Writers/ILanguageConventionService.cs index 435696d3f8..43a502ec95 100644 --- a/src/Kiota.Builder/Writers/ILanguageConventionService.cs +++ b/src/Kiota.Builder/Writers/ILanguageConventionService.cs @@ -8,9 +8,10 @@ public interface ILanguageConventionService string PathSegmentPropertyName {get; } string CurrentPathPropertyName {get; } string HttpCorePropertyName {get; } + string RawUrlPropertyName {get; } string ParseNodeInterfaceName {get; } string GetTypeString(CodeTypeBase code); - string TranslateType(string typeName); + string TranslateType(CodeType type); string GetParameterSignature(CodeParameter parameter); void WriteShortDescription(string description, LanguageWriter writer); } diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index e9c51c8b4b..d32c3c195a 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -31,10 +31,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri var queryStringParam = codeElement.Parameters.OfKind(CodeParameterKind.QueryParameter); var headersParam = codeElement.Parameters.OfKind(CodeParameterKind.Headers); var optionsParam = codeElement.Parameters.OfKind(CodeParameterKind.Options); - if(!codeElement.IsOverload) - foreach(var parameter in codeElement.Parameters.Where(x => !x.Optional).OrderBy(x => x.Name)) { - writer.WriteLine($"Objects.requireNonNull({parameter.Name});"); - } + AddNullChecks(codeElement, writer); switch(codeElement.MethodKind) { case CodeMethodKind.Serializer: WriteSerializerBody(parentClass, writer); @@ -65,7 +62,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri WriteApiConstructorBody(parentClass, codeElement, writer); break; case CodeMethodKind.Constructor when codeElement.IsOverload && parentClass.IsOfKind(CodeClassKind.RequestBuilder): - WriteRequestBuilderConstructorCall(parentClass, codeElement, writer); + WriteRequestBuilderConstructorCall(codeElement, writer); break; case CodeMethodKind.Constructor: WriteConstructorBody(parentClass, codeElement, writer, inherits); @@ -79,7 +76,12 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri writer.DecreaseIndent(); writer.WriteLine("}"); } - private void WriteRequestBuilderConstructorCall(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) + private static void AddNullChecks(CodeMethod codeElement, LanguageWriter writer) { + if(!codeElement.IsOverload) + foreach(var parameter in codeElement.Parameters.Where(x => !x.Optional).OrderBy(x => x.Name)) + writer.WriteLine($"Objects.requireNonNull({parameter.Name});"); + } + private static void WriteRequestBuilderConstructorCall(CodeMethod codeElement, LanguageWriter writer) { var httpCoreParameter = codeElement.Parameters.OfKind(CodeParameterKind.HttpCore); var currentPathParameter = codeElement.Parameters.OfKind(CodeParameterKind.CurrentPath); @@ -311,7 +313,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { } private string GetDeserializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name, propType.IsNullable); + var propertyType = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -336,7 +338,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType) { } private string GetSerializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name, propType.IsNullable); + var propertyType = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) diff --git a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs index 763b60c5c1..48049d362d 100644 --- a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs +++ b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs @@ -3,22 +3,22 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Java { - public class JavaConventionService : ILanguageConventionService + public class JavaConventionService : CommonLanguageConventionService { private const string _streamTypeName = "InputStream"; - public string StreamTypeName => _streamTypeName; + public override string StreamTypeName => _streamTypeName; private const string _voidTypeName = "Void"; - public string VoidTypeName => _voidTypeName; - public string DocCommentPrefix => " * "; - public string PathSegmentPropertyName => "pathSegment"; - public string CurrentPathPropertyName => "currentPath"; - public string HttpCorePropertyName => "httpCore"; - public string RawUrlPropertyName => "isRawUrl"; + public override string VoidTypeName => _voidTypeName; + public override string DocCommentPrefix => " * "; + public override string PathSegmentPropertyName => "pathSegment"; + public override string CurrentPathPropertyName => "currentPath"; + public override string HttpCorePropertyName => "httpCore"; + public override string RawUrlPropertyName => "isRawUrl"; internal HashSet PrimitiveTypes = new() {"String", "Boolean", "Integer", "Float", "Long", "Guid", "OffsetDateTime", _voidTypeName, _streamTypeName }; - public string ParseNodeInterfaceName => "ParseNode"; + public override string ParseNodeInterfaceName => "ParseNode"; internal string DocCommentStart = "/**"; internal string DocCommentEnd = " */"; - public string GetAccessModifier(AccessModifier access) + public override string GetAccessModifier(AccessModifier access) { return (access) switch { (AccessModifier.Public) => "public", @@ -27,18 +27,19 @@ public string GetAccessModifier(AccessModifier access) }; } - public string GetParameterSignature(CodeParameter parameter) + public override string GetParameterSignature(CodeParameter parameter) { - var nullAnnotation = parameter.Type.IsNullable ? $"@javax.annotation.{(parameter.Optional ? "Nullable" : "Nonnull")} " : string.Empty; + var nullKeyword = parameter.Optional ? "Nullable" : "Nonnull"; + var nullAnnotation = parameter.Type.IsNullable ? $"@javax.annotation.{nullKeyword} " : string.Empty; return $"{nullAnnotation}final {GetTypeString(parameter.Type)} {parameter.Name}"; } - public string GetTypeString(CodeTypeBase code) + public override string GetTypeString(CodeTypeBase code) { if(code is CodeUnionType) throw new InvalidOperationException($"Java does not support union types, the union type {code.Name} should have been filtered out by the refiner"); else if (code is CodeType currentType) { - var typeName = TranslateType(currentType.Name, currentType.IsNullable); + var typeName = TranslateType(currentType); var collectionPrefix = currentType.CollectionKind == CodeType.CodeTypeCollectionKind.Complex ? "List<" : string.Empty; var collectionSuffix = currentType.CollectionKind switch { CodeType.CodeTypeCollectionKind.Complex => ">", @@ -52,18 +53,13 @@ public string GetTypeString(CodeTypeBase code) } else throw new InvalidOperationException($"type of type {code.GetType()} is unknown"); } - public string TranslateType(string typeName){ - return TranslateType(typeName, false); - } - public string TranslateType(string typeName, bool isNullable) - { - return (typeName) switch {//TODO we're probably missing a bunch of type mappings - ("void" or "boolean") when !isNullable => typeName.ToFirstCharacterLowerCase(), //little casing hack - _ => typeName.ToFirstCharacterUpperCase() ?? "Object", + public override string TranslateType(CodeType type) { + return (type.Name) switch {//TODO we're probably missing a bunch of type mappings + ("void" or "boolean") when !type.IsNullable => type.Name.ToFirstCharacterLowerCase(), //little casing hack + _ => type.Name.ToFirstCharacterUpperCase() ?? "Object", }; } - - public void WriteShortDescription(string description, LanguageWriter writer) + public override void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) writer.WriteLine($"{DocCommentStart} {RemoveInvalidDescriptionCharacters(description)} {DocCommentEnd}"); diff --git a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs index 3c1c70110c..31336aa867 100644 --- a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs @@ -213,7 +213,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer) { } private string GetDeserializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -251,7 +251,7 @@ private static string TranslateObjectType(string typeName) } private string GetSerializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = conventions.TranslateType(propType.Name); + var propertyType = conventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) diff --git a/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs b/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs index df5c8b2fb6..d49f0a2b59 100644 --- a/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs +++ b/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs @@ -2,20 +2,21 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Ruby { - public class RubyConventionService : ILanguageConventionService + public class RubyConventionService : CommonLanguageConventionService { public static string SerializerFactoryPropertyName => "serializer_factory"; - public string StreamTypeName => "stdin"; + public override string StreamTypeName => "stdin"; private const string _voidTypeName = "nil"; - public string VoidTypeName => _voidTypeName; - public string DocCommentPrefix => "## "; - public string PathSegmentPropertyName => "path_segment"; - public string CurrentPathPropertyName => "current_path"; - public string HttpCorePropertyName => "http_core"; - public string ParseNodeInterfaceName => "parse_node"; + public override string VoidTypeName => _voidTypeName; + public override string DocCommentPrefix => "## "; + public override string PathSegmentPropertyName => "path_segment"; + public override string CurrentPathPropertyName => "current_path"; + public override string HttpCorePropertyName => "http_core"; + public override string ParseNodeInterfaceName => "parse_node"; + public override string RawUrlPropertyName => "is_raw_url"; internal string DocCommentStart = "## "; internal string DocCommentEnd = "## "; - public string GetAccessModifier(AccessModifier access) + public override string GetAccessModifier(AccessModifier access) { return (access) switch { (AccessModifier.Public) => "public", @@ -23,26 +24,26 @@ public string GetAccessModifier(AccessModifier access) _ => "private", }; } - public string GetParameterSignature(CodeParameter parameter) + public override string GetParameterSignature(CodeParameter parameter) { return $"{parameter.Name}{(parameter.Optional ? "=nil" : string.Empty)}"; } - public string GetTypeString(CodeTypeBase code) + public override string GetTypeString(CodeTypeBase code) { if (code is CodeType currentType) { - return $"{TranslateType(currentType.Name)}"; + return $"{TranslateType(currentType)}"; } else throw new InvalidOperationException(); } - public string TranslateType(string typeName) + public override string TranslateType(CodeType type) { - return (typeName) switch { + return (type.Name) switch { "integer" => "number", - "float" or "string" or "object" or "boolean" or "void" => typeName, // little casing hack - _ => typeName.ToFirstCharacterUpperCase() ?? "object", + "float" or "string" or "object" or "boolean" or "void" => type.Name, // little casing hack + _ => type.Name.ToFirstCharacterUpperCase() ?? "object", }; } - public void WriteShortDescription(string description, LanguageWriter writer) + public override void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) { writer.WriteLine($"{DocCommentPrefix}"); diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs index 22a6b1791a..30e215be8e 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs @@ -253,7 +253,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string } private string GetDeserializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = localConventions.TranslateType(propType.Name); + var propertyType = localConventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) @@ -276,7 +276,7 @@ private string GetDeserializationMethodName(CodeTypeBase propType) { } private string GetSerializationMethodName(CodeTypeBase propType) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; - var propertyType = localConventions.TranslateType(propType.Name); + var propertyType = localConventions.TranslateType(propType); if(propType is CodeType currentType) { if(isCollection) if(currentType.TypeDefinition == null) diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index b5fe5fe165..69d2831895 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -3,28 +3,28 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.TypeScript { - public class TypeScriptConventionService : ILanguageConventionService + public class TypeScriptConventionService : CommonLanguageConventionService { public TypeScriptConventionService(LanguageWriter languageWriter) { writer = languageWriter; } private readonly LanguageWriter writer; - public string StreamTypeName => "ReadableStream"; + public override string StreamTypeName => "ReadableStream"; - public string VoidTypeName => throw new System.NotImplementedException(); + public override string VoidTypeName => throw new System.NotImplementedException(); - public string DocCommentPrefix => " * "; + public override string DocCommentPrefix => " * "; - public string PathSegmentPropertyName => "pathSegment"; + public override string PathSegmentPropertyName => "pathSegment"; - public string CurrentPathPropertyName => "currentPath"; + public override string CurrentPathPropertyName => "currentPath"; - public string HttpCorePropertyName => "httpCore"; + public override string HttpCorePropertyName => "httpCore"; - public string ParseNodeInterfaceName => "ParseNode"; + public override string ParseNodeInterfaceName => "ParseNode"; - public string RawUrlPropertyName => "isRawUrl"; + public override string RawUrlPropertyName => "isRawUrl"; internal string DocCommentStart = "/**"; internal string DocCommentEnd = " */"; @@ -33,7 +33,7 @@ internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, Lang writer.WriteLines($"return new {returnType}({currentPath}this.{PathSegmentPropertyName}{suffix}, this.{HttpCorePropertyName}, false);"); } - public string GetAccessModifier(AccessModifier access) + public override string GetAccessModifier(AccessModifier access) { return access switch { AccessModifier.Public => "public", @@ -42,19 +42,19 @@ public string GetAccessModifier(AccessModifier access) }; } - public string GetParameterSignature(CodeParameter parameter) + public override string GetParameterSignature(CodeParameter parameter) { var defaultValueSuffiix = string.IsNullOrEmpty(parameter.DefaultValue) ? string.Empty : $" = {parameter.DefaultValue}"; return $"{parameter.Name}{(parameter.Optional && parameter.Type.IsNullable ? "?" : string.Empty)}: {GetTypeString(parameter.Type)}{(parameter.Type.IsNullable ? " | undefined": string.Empty)}{defaultValueSuffiix}"; } - public string GetTypeString(CodeTypeBase code) + public override string GetTypeString(CodeTypeBase code) { var collectionSuffix = code.CollectionKind == CodeType.CodeTypeCollectionKind.None ? string.Empty : "[]"; if(code is CodeUnionType currentUnion && currentUnion.Types.Any()) return currentUnion.Types.Select(x => GetTypeString(x)).Aggregate((x, y) => $"{x} | {y}") + collectionSuffix; else if(code is CodeType currentType) { - var typeName = TranslateType(currentType.Name); + var typeName = TranslateType(currentType); if (code.ActionOf) return WriteInlineDeclaration(currentType); else @@ -85,13 +85,13 @@ private string WriteInlineDeclaration(CodeType currentType) { return $"{{{innerDeclaration}}}"; } - public string TranslateType(string typeName) + public override string TranslateType(CodeType type) { - return (typeName) switch {//TODO we're probably missing a bunch of type mappings + return (type.Name) switch {//TODO we're probably missing a bunch of type mappings "integer" => "number", "double" => "number", - "string" or "object" or "boolean" or "void" => typeName, // little casing hack - _ => typeName.ToFirstCharacterUpperCase() ?? "object", + "string" or "object" or "boolean" or "void" => type.Name, // little casing hack + _ => type.Name.ToFirstCharacterUpperCase() ?? "object", }; } public bool IsPrimitiveType(string typeName) { @@ -101,7 +101,7 @@ public bool IsPrimitiveType(string typeName) { }; } internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription?.Replace("\\", "/"); - public void WriteShortDescription(string description, LanguageWriter writer) + public override void WriteShortDescription(string description, LanguageWriter writer) { if(!string.IsNullOrEmpty(description)) writer.WriteLine($"{DocCommentStart} {RemoveInvalidDescriptionCharacters(description)} {DocCommentEnd}"); From 20721fd082dd8d1ffa6ea403d34f64d7ce270db2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 15:11:50 -0400 Subject: [PATCH 14/23] - updates go method writer unit test --- tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs index 316232e936..be673a8871 100644 --- a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs @@ -168,8 +168,8 @@ public void WritesRequestGeneratorBody() { AddRequestBodyParameters(); writer.Write(method); var result = tw.ToString(); - Assert.Contains($"requestInfo := new({abstractionsPackageHash}.RequestInfo)", result); - Assert.Contains("requestInfo.URI = *uri", result); + Assert.Contains($"requestInfo := {abstractionsPackageHash}.NewRequestInfo()", result); + Assert.Contains("err := requestInfo.SetUri", result); Assert.Contains($"Method = {abstractionsPackageHash}.GET", result); Assert.Contains("err != nil", result); Assert.Contains("h != nil", result); From e55a02af40f5b721e744af8c37678614cab0cb4f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 15:36:46 -0400 Subject: [PATCH 15/23] - adds the set URI method for ruby --- .../request_info.rb | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/request_info.rb b/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/request_info.rb index a470334c96..edf0ba6789 100644 --- a/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/request_info.rb +++ b/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/request_info.rb @@ -23,6 +23,30 @@ def headers @headers ||= Hash.new end + def set_uri(current_path, path_segment, is_raw_url) + if is_raw_url + if current_path.nil? || current_path.empty? + raise ArgumentError, 'current_path cannot be nil or empty' + end + question_mark_splat = current_path.split(/\?/) + scheme_host_and_path = question_mark_splat[0] + if question_mark_splat.length > 1 + query_parameters = question_mark_splat[1] + query_parameters.split(/&/).each do |query_parameter| + key_value_pair = query_parameter.split(/=/) + if key_value_pair.length > 1 + query_parameters[key_value_pair[0]] = key_value_pair[1] + elsif key_value_pair.length == 1 + query_parameters[key_value_pair[0]] = nil + end + end + end + @uri = URI(current_path) + else + @uri = URI(current_path + path_segment) + end + end + def set_stream_content(value = $stdin) @content = value @headers[@@content_type_header] = @@binary_content_type From 1eb43db5f98de62e3a44e338c171e49574db2a60 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 15:46:32 -0400 Subject: [PATCH 16/23] - adds support for raw URL in ruby --- src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs | 6 ++++-- src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs index 31336aa867..5269c44eae 100644 --- a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs @@ -86,6 +86,7 @@ private static void WriteConstructorBody(CodeClass parentClass, CodeMethod curre if(currentMethod.IsOfKind(CodeMethodKind.Constructor)) { AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.HttpCore, CodePropertyKind.HttpCore, writer); AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.CurrentPath, CodePropertyKind.CurrentPath, writer); + AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RawUrl, CodePropertyKind.RawUrl, writer); } } private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMethod currentMethod, CodeParameterKind parameterKind, CodePropertyKind propertyKind, LanguageWriter writer) { @@ -159,7 +160,7 @@ private void WriteRequestExecutorBody(CodeMethod codeElement, CodeParameter requ private void WriteRequestGeneratorBody(CodeMethod codeElement, CodeParameter requestBodyParam, CodeParameter queryStringParam, CodeParameter headersParam, LanguageWriter writer) { if(codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null"); writer.WriteLines("request_info = MicrosoftKiotaAbstractions::RequestInfo.new()", - $"request_info.uri = @{conventions.CurrentPathPropertyName} + @{conventions.PathSegmentPropertyName}", + $"request_info.set_uri(@{conventions.CurrentPathPropertyName}, @{conventions.PathSegmentPropertyName}, @{conventions.RawUrlPropertyName})", $"request_info.http_method = :{codeElement.HttpMethod?.ToString().ToUpperInvariant()}"); if(headersParam != null) writer.WriteLine($"request_info.set_headers_from_raw_object(h)"); @@ -183,6 +184,7 @@ private void WriteSerializerBody(CodeClass parentClass, LanguageWriter writer) { if(additionalDataProperty != null) writer.WriteLine($"writer.write_additional_data(@{additionalDataProperty.Name.ToSnakeCase()})"); } + private static CodeParameterOrderComparer parameterOrderComparer = new CodeParameterOrderComparer(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer) { var methodName = (code.MethodKind switch { (CodeMethodKind.Constructor or CodeMethodKind.ClientConstructor) => $"initialize", @@ -190,7 +192,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer) { (CodeMethodKind.Setter) => $"{code.AccessedProperty?.Name?.ToSnakeCase()}", _ => code.Name.ToSnakeCase() }); - var parameters = string.Join(", ", code.Parameters.Select(p=> conventions.GetParameterSignature(p).ToSnakeCase()).ToList()); + var parameters = string.Join(", ", code.Parameters.OrderBy(x => x, parameterOrderComparer).Select(p=> conventions.GetParameterSignature(p).ToSnakeCase()).ToList()); writer.WriteLine($"def {methodName.ToSnakeCase()}({parameters}) "); writer.IncreaseIndent(); } diff --git a/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs b/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs index d49f0a2b59..732132de94 100644 --- a/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs +++ b/src/Kiota.Builder/Writers/Ruby/RubyConventionService.cs @@ -26,7 +26,8 @@ public override string GetAccessModifier(AccessModifier access) } public override string GetParameterSignature(CodeParameter parameter) { - return $"{parameter.Name}{(parameter.Optional ? "=nil" : string.Empty)}"; + var defaultValue = parameter.Optional ? $"={(parameter.DefaultValue ?? "nil")}" : string.Empty; + return $"{parameter.Name}{defaultValue}"; } public override string GetTypeString(CodeTypeBase code) { @@ -60,7 +61,7 @@ public string GetNormalizedNamespacePrefixForType(CodeTypeBase type) { internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription?.Replace("\\", "#"); internal void AddRequestBuilderBody(bool addCurrentPath, string returnType, LanguageWriter writer, string suffix = default, string prefix = default) { var currentPath = addCurrentPath ? $"@{CurrentPathPropertyName} + " : string.Empty; - writer.WriteLine($"{prefix}{returnType.ToFirstCharacterUpperCase()}.new({currentPath}@{PathSegmentPropertyName} {suffix}, @{HttpCorePropertyName})"); + writer.WriteLine($"{prefix}{returnType.ToFirstCharacterUpperCase()}.new({currentPath}@{PathSegmentPropertyName} {suffix}, @{HttpCorePropertyName}, false)"); } } } From 9b934774bb548356ed8052869ef9fe2711199568 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 16:17:00 -0400 Subject: [PATCH 17/23] - fixes a bug where ruby api client would import wrong default serialization modules --- src/Kiota.Builder/Refiners/RubyRefiner.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index bbb3d5a8d5..465106a1c6 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -24,6 +24,8 @@ public override void Refine(CodeNamespace generatedCode) AddNamespaceModuleImports(generatedCode , _configuration.ClientNamespaceName); FixReferencesToEntityType(generatedCode); FixInheritedEntityType(generatedCode); + ReplaceDefaultSerializationModules(generatedCode, "microsoft_kiota_serialization.JsonSerializationWriterFactory"); + ReplaceDefaultDeserializationModules(generatedCode, "microsoft_kiota_serialization.JsonParseNodeFactory"); AddSerializationModulesImport(generatedCode, new [] { "microsoft_kiota_abstractions.ApiClientBuilder", "microsoft_kiota_abstractions.SerializationWriterFactoryRegistry" }, From 2eba6b7f696779bc4cf07cef6663ff16abb5dcda Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 23 Aug 2021 16:19:30 -0400 Subject: [PATCH 18/23] - adds changelog entry for raw URLs --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0958bced6c..327cef7737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixes a bug where generated models would be tied to a specific backing store implementation #400 - Fixed #428 a bug where inline double defintion would make code dom generation fail - Revamped authentication provider interface to allow multiple authentication schemes #498 +- Fixed a bug preventing from using request builders with raw URls #508 ## [0.0.7] - 2021-08-04 From 77198e0a35784a81db05631bf5c06acea772e5f6 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 24 Aug 2021 13:23:41 +0000 Subject: [PATCH 19/23] - adds tests for code parameters comparer Signed-off-by: GitHub --- .../CodeDOM/CodeParameterOrderComparerTests.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs diff --git a/tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs b/tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs new file mode 100644 index 0000000000..7aaac788ef --- /dev/null +++ b/tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs @@ -0,0 +1,17 @@ +using Xunit; +using Moq; + +namespace Kiota.Builder.Tests { + public class CodeParameterOrderComparerTests { + [Fact] + public void DefensiveProgramming() { + var comparer = new CodeParameterOrderComparer(); + Assert.NotNull(comparer); + var root = CodeNamespace.InitRootNamespace(); + var mockParameter = new Mock(root).Object; + Assert.Equal(0, comparer.Compare(null, null)); + Assert.Equal(-1, comparer.Compare(null, mockParameter)); + Assert.Equal(1, comparer.Compare(mockParameter, null)); + } + } +} From c25efa7e02e3a36789635afa2dfb6101fa92eee2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 24 Aug 2021 13:48:00 +0000 Subject: [PATCH 20/23] - adds unit tests for common language convention service Signed-off-by: GitHub --- .../CommonLanguageConventionServiceTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/Kiota.Builder.Tests/Writers/CommonLanguageConventionServiceTests.cs diff --git a/tests/Kiota.Builder.Tests/Writers/CommonLanguageConventionServiceTests.cs b/tests/Kiota.Builder.Tests/Writers/CommonLanguageConventionServiceTests.cs new file mode 100644 index 0000000000..ffceeec6cc --- /dev/null +++ b/tests/Kiota.Builder.Tests/Writers/CommonLanguageConventionServiceTests.cs @@ -0,0 +1,27 @@ +using Kiota.Builder.Writers.CSharp; +using Xunit; +using Moq; +using System; + + +namespace Kiota.Builder.Tests.Writers { + public class CommonLanguageConventionServiceTests { + [Fact] + public void TranslatesType() { + var service = new CSharpConventionService(); + var root = CodeNamespace.InitRootNamespace(); + var unknownTypeMock = new Mock(root); + unknownTypeMock.Setup(x => x.Name).Returns("unkownType"); + Assert.Throws(() => service.TranslateType(unknownTypeMock.Object)); + var stringType = new CodeType(root) { + Name = "string" + }; + Assert.Equal("string", service.TranslateType(stringType)); + var unionStringType = new CodeUnionType(root) { + Name = "unionString" + }; + unionStringType.Types.Add(stringType); + Assert.Equal("string", service.TranslateType(unionStringType)); + } + } +} From 4c9df70212ab06e846ba9b3b73be947f3b6f22e2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 24 Aug 2021 14:00:30 +0000 Subject: [PATCH 21/23] - updates unit test for request generators Signed-off-by: GitHub --- .../Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs | 1 + tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs | 1 + tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs | 1 + .../Writers/TypeScript/CodeMethodWriterTests.cs | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs index 96918f2360..2df3dc93c3 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs @@ -161,6 +161,7 @@ public void WritesRequestGeneratorBody() { var result = tw.ToString(); Assert.Contains("var requestInfo = new RequestInfo", result); Assert.Contains("HttpMethod = HttpMethod.GET", result); + Assert.Contains("requestInfo.SetURI", result); Assert.Contains("h?.Invoke", result); Assert.Contains("AddQueryParameters", result); Assert.Contains("SetContentFromParsable", result); diff --git a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs index ec70b65455..740609ddf5 100644 --- a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs @@ -171,6 +171,7 @@ public void WritesRequestGeneratorBody() { writer.Write(method); var result = tw.ToString(); Assert.Contains("final RequestInfo requestInfo = new RequestInfo()", result); + Assert.Contains("this.setUri", result); Assert.Contains("httpMethod = HttpMethod.GET", result); Assert.Contains("h.accept(requestInfo.headers)", result); Assert.Contains("AddQueryParameters", result); diff --git a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs index 936e98f1c0..fe512a0378 100644 --- a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs @@ -187,6 +187,7 @@ public void WritesRequestGeneratorBody() { writer.Write(method); var result = tw.ToString(); Assert.Contains("request_info = MicrosoftKiotaAbstractions::RequestInfo.new()", result); + Assert.Contains("request_info.set_uri", result); Assert.Contains("http_method = :GET", result); Assert.Contains("set_query_string_parameters_from_raw_object", result); Assert.Contains("set_content_from_parsable", result); diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs index 443f19557a..d91c65cd33 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs @@ -160,6 +160,7 @@ public void WritesRequestGeneratorBody() { var result = tw.ToString(); Assert.Contains("const requestInfo = new RequestInfo()", result); Assert.Contains("requestInfo.httpMethod = HttpMethod", result); + Assert.Contains("requestInfo.setUri", result); Assert.Contains("setHeadersFromRawObject", result); Assert.Contains("setQueryStringParametersFromRawObject", result); Assert.Contains("setContentFromParsable", result); From 12c4231b6e3d66e85a8e76727fc8d32d1c28f245 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 24 Aug 2021 14:09:15 +0000 Subject: [PATCH 22/23] - bumps patch version for abstractions Signed-off-by: GitHub --- abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj | 2 +- abstractions/java/lib/build.gradle | 2 +- .../lib/microsoft_kiota_abstractions/version.rb | 2 +- abstractions/typescript/package-lock.json | 2 +- abstractions/typescript/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj b/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj index c3833e5301..c30ecb3b15 100644 --- a/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj +++ b/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj @@ -5,7 +5,7 @@ net5.0 true https://github.com/microsoft/kiota - 1.0.17 + 1.0.18 true true diff --git a/abstractions/java/lib/build.gradle b/abstractions/java/lib/build.gradle index 59a62893ab..af7024b878 100644 --- a/abstractions/java/lib/build.gradle +++ b/abstractions/java/lib/build.gradle @@ -46,7 +46,7 @@ publishing { publications { gpr(MavenPublication) { artifactId 'kiota-abstractions' - version '1.0.17' + version '1.0.18' from(components.java) } } diff --git a/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/version.rb b/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/version.rb index 036e8063a7..cb73d1ca17 100644 --- a/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/version.rb +++ b/abstractions/ruby/microsoft_kiota_abstractions/lib/microsoft_kiota_abstractions/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module MicrosoftKiotaAbstractions - VERSION = "0.1.4" + VERSION = "0.1.5" end diff --git a/abstractions/typescript/package-lock.json b/abstractions/typescript/package-lock.json index 2137789333..37d6e6161f 100644 --- a/abstractions/typescript/package-lock.json +++ b/abstractions/typescript/package-lock.json @@ -1,6 +1,6 @@ { "name": "@microsoft/kiota-abstractions", - "version": "1.0.17", + "version": "1.0.18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/abstractions/typescript/package.json b/abstractions/typescript/package.json index 35a3ebe382..0c983b2a38 100644 --- a/abstractions/typescript/package.json +++ b/abstractions/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/kiota-abstractions", - "version": "1.0.17", + "version": "1.0.18", "description": "Core abstractions for kiota generated libraries in TypeScript and JavaScript", "main": "dist/index.js", "types": "dist/index.d.ts", From ada8b7539574b59e21d29dcfdf9c4eeebacd9c37 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 25 Aug 2021 07:34:56 -0400 Subject: [PATCH 23/23] Apply suggestions from code review --- abstractions/dotnet/src/RequestInfo.cs | 11 ++++++++--- src/Kiota.Builder/CodeParameterOrderComparer.cs | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/abstractions/dotnet/src/RequestInfo.cs b/abstractions/dotnet/src/RequestInfo.cs index 4641d4b2e8..805e94223f 100644 --- a/abstractions/dotnet/src/RequestInfo.cs +++ b/abstractions/dotnet/src/RequestInfo.cs @@ -25,8 +25,11 @@ public class RequestInfo /// the current path (scheme, host, port, path, query parameters) of the request. /// the segment to append to the current path. /// whether the path segment is a raw url. When true, the segment is not happened and the current path is parsed for query parameters. - public void SetURI(string currentPath, string pathSegment, bool isRawUrl) { - if (isRawUrl) { + /// Thrown when the built URI is an invalid format. + public void SetURI(string currentPath, string pathSegment, bool isRawUrl) + { + if (isRawUrl) + { if(string.IsNullOrEmpty(currentPath)) throw new ArgumentNullException(nameof(currentPath)); var parseUri = new Uri(currentPath); @@ -34,7 +37,9 @@ public void SetURI(string currentPath, string pathSegment, bool isRawUrl) { QueryParameters.Add(qsp[0], qsp.Length > 1 ? qsp[1] : null); } URI = new Uri(parseUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped)); - } else { + } + else + { URI = new Uri(currentPath + pathSegment); } } diff --git a/src/Kiota.Builder/CodeParameterOrderComparer.cs b/src/Kiota.Builder/CodeParameterOrderComparer.cs index 3c1c1a71dc..a448d37727 100644 --- a/src/Kiota.Builder/CodeParameterOrderComparer.cs +++ b/src/Kiota.Builder/CodeParameterOrderComparer.cs @@ -24,9 +24,9 @@ private static int getKindOrderHint(CodeParameterKind kind) { CodeParameterKind.ResponseHandler => 7, CodeParameterKind.Serializer => 8, CodeParameterKind.BackingStore => 9, - CodeParameterKind.Custom => 12, - CodeParameterKind.RequestBody => 11, CodeParameterKind.SetterValue => 10, + CodeParameterKind.RequestBody => 11, + CodeParameterKind.Custom => 12, _ => 13, }; }