From a8c177de72cadc2a5fea200b1999c69cc1bdb2b1 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 27 Nov 2023 13:12:56 -0500 Subject: [PATCH 01/16] - refactoring: all regexes use a generate attribute Signed-off-by: Vincent Biret --- .../StructuredMimeTypesCollection.cs | 7 ++- src/Kiota.Builder/Constants.cs | 6 +-- .../OpenApiServerComparer.cs | 5 +- .../Extensions/OpenApiOperationExtensions.cs | 7 +-- .../OpenApiUrlTreeNodeExtensions.cs | 48 +++++++++++-------- .../Extensions/StringExtensions.cs | 13 ++--- src/Kiota.Builder/KiotaBuilder.cs | 7 ++- src/Kiota.Builder/Refiners/RubyRefiner.cs | 2 +- .../Writers/CLI/CliCodeMethodWriter.cs | 21 ++++---- .../Writers/Java/CodeMethodWriter.cs | 7 +-- .../Writers/Java/JavaConventionService.cs | 7 +-- .../Writers/Php/CodeEnumWriter.cs | 7 +-- src/kiota/KiotaHost.cs | 12 +++-- src/kiota/Rpc/Server.cs | 7 +-- 14 files changed, 81 insertions(+), 75 deletions(-) diff --git a/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs b/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs index 6f26e18d12..8e36bb980f 100644 --- a/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs +++ b/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs @@ -127,9 +127,8 @@ public IEnumerable GetContentTypes(IEnumerable searchTypes) .ThenByDescending(static x => x.Key, StringComparer.OrdinalIgnoreCase) .Select(static x => x.Key); } - [GeneratedRegex(@"[^/+]+\+", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline, 2000)] + [GeneratedRegex(@"[^/+]+\+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)] private static partial Regex vendorStripRegex(); - private readonly static Regex vendorStripRegexInstance = vendorStripRegex(); private bool TryGetMimeType(string mimeType, out float result) { if (string.IsNullOrEmpty(mimeType)) @@ -140,10 +139,10 @@ private bool TryGetMimeType(string mimeType, out float result) return _mimeTypes.TryGetValue(mimeType, out result) || // vendor and parameters mimeType.Contains('+', StringComparison.OrdinalIgnoreCase) && - _mimeTypes.TryGetValue(vendorStripRegexInstance.Replace(mimeType, string.Empty), out result) || // no vendor with parameters + _mimeTypes.TryGetValue(vendorStripRegex().Replace(mimeType, string.Empty), out result) || // no vendor with parameters mimeType.Contains(';', StringComparison.OrdinalIgnoreCase) && mimeType.Split(';', StringSplitOptions.RemoveEmptyEntries)[0] is string noParametersMimeType && (_mimeTypes.TryGetValue(noParametersMimeType, out result) || // vendor without parameters - _mimeTypes.TryGetValue(vendorStripRegexInstance.Replace(noParametersMimeType, string.Empty), out result)); // no vendor without parameters + _mimeTypes.TryGetValue(vendorStripRegex().Replace(noParametersMimeType, string.Empty), out result)); // no vendor without parameters } } diff --git a/src/Kiota.Builder/Constants.cs b/src/Kiota.Builder/Constants.cs index a1a9400621..1968837aa6 100644 --- a/src/Kiota.Builder/Constants.cs +++ b/src/Kiota.Builder/Constants.cs @@ -1,10 +1,6 @@ -using System; - -namespace Kiota.Builder; +namespace Kiota.Builder; public static class Constants { public const string DefaultOpenApiLabel = "default"; - public const string RawUrlParameterName = "request-raw-url"; - public static readonly TimeSpan DefaultRegexTimeout = TimeSpan.FromMilliseconds(100); public const string TempDirectoryName = "kiota"; } diff --git a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs index da206ac7c5..dca85c9a02 100644 --- a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs +++ b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs @@ -8,9 +8,8 @@ namespace Kiota.Builder.EqualityComparers; internal sealed partial class OpenApiServerComparer : IEqualityComparer { - private static readonly Regex _protocolCleanupRegex = GetCleanupRegex(); [GeneratedRegex("^https?://", RegexOptions.IgnoreCase | RegexOptions.Compiled, 200)] - private static partial Regex GetCleanupRegex(); + private static partial Regex protocolCleanupRegex(); public bool Equals(OpenApiServer? x, OpenApiServer? y) { return x != null && y != null && GetHashCode(x) == GetHashCode(y); @@ -19,6 +18,6 @@ public int GetHashCode([DisallowNull] OpenApiServer obj) { if (string.IsNullOrEmpty(obj?.Url)) return 0; - return _protocolCleanupRegex.Replace(obj.Url, string.Empty).GetHashCode(StringComparison.OrdinalIgnoreCase); + return protocolCleanupRegex().Replace(obj.Url, string.Empty).GetHashCode(StringComparison.OrdinalIgnoreCase); } } diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index 767ac3696a..7995564db5 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -6,13 +6,14 @@ using Microsoft.OpenApi.Models; namespace Kiota.Builder.Extensions; -public static class OpenApiOperationExtensions +public static partial class OpenApiOperationExtensions { internal static readonly HashSet SuccessCodes = new(StringComparer.OrdinalIgnoreCase) { "200", "201", "202", "203", "206", "2XX" }; //204 excluded as it won't have a schema + [GeneratedRegex(@"[^/]+\+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] + private static partial Regex vendorSpecificCleanup(); /// /// cleans application/vnd.github.mercy-preview+json to application/json /// - private static readonly Regex vendorSpecificCleanup = new(@"[^/]+\+", RegexOptions.Compiled, Constants.DefaultRegexTimeout); internal static OpenApiSchema? GetResponseSchema(this OpenApiOperation operation, StructuredMimeTypesCollection structuredMimeTypes) { ArgumentNullException.ThrowIfNull(operation); @@ -48,7 +49,7 @@ internal static IEnumerable GetValidSchemas(this IDictionary !string.IsNullOrEmpty(c.Key)) .Select(static c => (Key: c.Key.Split(';', StringSplitOptions.RemoveEmptyEntries)[0], c.Value)) - .Where(c => structuredMimeTypes.Contains(c.Key) || structuredMimeTypes.Contains(vendorSpecificCleanup.Replace(c.Key, string.Empty))) + .Where(c => structuredMimeTypes.Contains(c.Key) || structuredMimeTypes.Contains(vendorSpecificCleanup().Replace(c.Key, string.Empty))) .Select(static co => co.Value.Schema) .Where(static s => s is not null); } diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs index 3282ccba7a..4f3b65ae21 100644 --- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -8,7 +8,7 @@ using Microsoft.OpenApi.Services; namespace Kiota.Builder.Extensions; -public static class OpenApiUrlTreeNodeExtensions +public static partial class OpenApiUrlTreeNodeExtensions { private static string GetDotIfBothNotNullOfEmpty(string x, string y) => string.IsNullOrEmpty(x) || string.IsNullOrEmpty(y) ? string.Empty : "."; private static readonly Func replaceSingleParameterSegmentByItem = @@ -38,9 +38,11 @@ public static string GetNodeNamespaceFromPath(this OpenApiUrlTreeNode currentNod return currentNode.Path.GetNamespaceFromPath(prefix); } //{id}, name(idParam={id}), name(idParam='{id}'), name(idParam='{id}',idParam2='{id2}') - private static readonly Regex PathParametersRegex = new(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Singleline, 100)] + private static partial Regex PathParametersRegex(); // microsoft.graph.getRoleScopeTagsByIds(ids=@ids) - private static readonly Regex AtSignPathParameterRegex = new(@"=@(\w+)", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 100)] + private static partial Regex AtSignPathParameterRegex(); private const char RequestParametersChar = '{'; private const char RequestParametersEndChar = '}'; private const string RequestParametersSectionChar = "("; @@ -52,8 +54,8 @@ private static string CleanupParametersFromPath(string pathSegment) { if (string.IsNullOrEmpty(pathSegment)) return pathSegment; - return PathParametersRegex.Replace( - AtSignPathParameterRegex.Replace(pathSegment, "={$1}"), + return PathParametersRegex().Replace( + AtSignPathParameterRegex().Replace(pathSegment, "={$1}"), requestParametersMatchEvaluator) .Replace(RequestParametersSectionEndChar, string.Empty, StringComparison.OrdinalIgnoreCase) .Replace(RequestParametersSectionChar, string.Empty, StringComparison.OrdinalIgnoreCase); @@ -79,7 +81,8 @@ public static IEnumerable GetPathParametersForCurrentSegment(t return Enumerable.Empty(); } private const char PathNameSeparator = '\\'; - private static readonly Regex idClassNameCleanup = new(@"-?id\d?}?$", RegexOptions.Compiled | RegexOptions.IgnoreCase, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"-?id\d?}?$", RegexOptions.Singleline | RegexOptions.IgnoreCase, 100)] + private static partial Regex idClassNameCleanup(); /// /// Returns the class name for the node with more or less precision depending on the provided arguments /// @@ -109,11 +112,11 @@ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, Struct CleanupParametersFromPath(currentNode.Segment)?.ReplaceValueIdentifier())); if (!string.IsNullOrEmpty(rawClassName) && string.IsNullOrEmpty(referenceName)) { - if (stripExtensionForIndexersTestRegex.IsMatch(rawClassName)) - rawClassName = stripExtensionForIndexersRegex.Replace(rawClassName, string.Empty); - if ((currentNode?.DoesNodeBelongToItemSubnamespace() ?? false) && idClassNameCleanup.IsMatch(rawClassName)) + if (stripExtensionForIndexersTestRegex().IsMatch(rawClassName)) + rawClassName = stripExtensionForIndexersRegex().Replace(rawClassName, string.Empty); + if ((currentNode?.DoesNodeBelongToItemSubnamespace() ?? false) && idClassNameCleanup().IsMatch(rawClassName)) { - rawClassName = idClassNameCleanup.Replace(rawClassName, string.Empty); + rawClassName = idClassNameCleanup().Replace(rawClassName, string.Empty); if (WithKeyword.Equals(rawClassName, StringComparison.Ordinal)) // in case the single parameter doesn't follow {classname-id} we get the previous segment rawClassName = currentNode.Path .Split(PathNameSeparator, StringSplitOptions.RemoveEmptyEntries) @@ -139,8 +142,9 @@ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, Struct "yml", "txt", }; - private static readonly Regex descriptionCleanupRegex = new(@"[\r\n\t]", RegexOptions.Compiled, Constants.DefaultRegexTimeout); - public static string CleanupDescription(this string? description) => string.IsNullOrEmpty(description) ? string.Empty : descriptionCleanupRegex.Replace(description, string.Empty); + [GeneratedRegex(@"[\r\n\t]", RegexOptions.Singleline, 100)] + private static partial Regex descriptionCleanupRegex(); + public static string CleanupDescription(this string? description) => string.IsNullOrEmpty(description) ? string.Empty : descriptionCleanupRegex().Replace(description, string.Empty); public static string GetPathItemDescription(this OpenApiUrlTreeNode currentNode, string label, string? defaultValue = default) { if (currentNode != null && !string.IsNullOrEmpty(label) && currentNode.PathItems.TryGetValue(label, out var pathItem)) @@ -158,7 +162,7 @@ public static bool IsPathSegmentWithSingleSimpleParameter(this OpenApiUrlTreeNod private static bool IsPathSegmentWithSingleSimpleParameter(this string currentSegment) { if (string.IsNullOrEmpty(currentSegment)) return false; - var segmentWithoutExtension = stripExtensionForIndexersRegex.Replace(currentSegment, string.Empty); + var segmentWithoutExtension = stripExtensionForIndexersRegex().Replace(currentSegment, string.Empty); return segmentWithoutExtension.StartsWith(RequestParametersChar) && segmentWithoutExtension.EndsWith(RequestParametersEndChar) && @@ -170,8 +174,10 @@ private static bool IsPathSegmentWithNumberOfParameters(this string currentSegme return eval(currentSegment.Where(static x => x == RequestParametersChar)); } - private static readonly Regex stripExtensionForIndexersRegex = new(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Compiled, Constants.DefaultRegexTimeout); // so {param-name}.json is considered as indexer - private static readonly Regex stripExtensionForIndexersTestRegex = new(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Compiled, Constants.DefaultRegexTimeout); // so {param-name}.json is considered as indexer + [GeneratedRegex(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 100)] + private static partial Regex stripExtensionForIndexersRegex(); // so {param-name}.json is considered as indexer + [GeneratedRegex(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 100)] + private static partial Regex stripExtensionForIndexersTestRegex(); // so {param-name}.json is considered as indexer public static bool IsComplexPathMultipleParameters(this OpenApiUrlTreeNode currentNode) => (currentNode?.Segment?.IsPathSegmentWithNumberOfParameters(static x => x.Any()) ?? false) && !currentNode.IsPathSegmentWithSingleSimpleParameter(); public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode) @@ -209,11 +215,12 @@ public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode) SanitizePathParameterNamesForUrlTemplate(currentNode.Path.Replace('\\', '/'), pathReservedPathParametersIds) + queryStringParameters; } - private static readonly Regex pathParamMatcher = new(@"{(?[^}]+)}", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"{(?[^}]+)}", RegexOptions.Singleline, 100)] + private static partial Regex pathParamMatcher(); private static string SanitizePathParameterNamesForUrlTemplate(string original, HashSet reservedParameterNames) { if (string.IsNullOrEmpty(original) || !original.Contains('{', StringComparison.OrdinalIgnoreCase)) return original; - var parameters = pathParamMatcher.Matches(original); + var parameters = pathParamMatcher().Matches(original); foreach (var value in parameters.Select(x => x.Groups["paramname"].Value)) original = original.Replace(value, (reservedParameterNames.Contains(value) ? "+" : string.Empty) + value.SanitizeParameterNameForUrlTemplate(), StringComparison.Ordinal); return original; @@ -221,7 +228,7 @@ private static string SanitizePathParameterNamesForUrlTemplate(string original, public static string SanitizeParameterNameForUrlTemplate(this string original) { if (string.IsNullOrEmpty(original)) return original; - return Uri.EscapeDataString(stripExtensionForIndexersRegex + return Uri.EscapeDataString(stripExtensionForIndexersRegex() .Replace(original, string.Empty) // {param-name}.json becomes {param-name} .TrimStart('{') .TrimEnd('}')) @@ -229,10 +236,11 @@ public static string SanitizeParameterNameForUrlTemplate(this string original) .Replace(".", "%2E", StringComparison.OrdinalIgnoreCase) .Replace("~", "%7E", StringComparison.OrdinalIgnoreCase);// - . ~ are invalid uri template character but don't get encoded by Uri.EscapeDataString } - private static readonly Regex removePctEncodedCharacters = new(@"%[0-9A-F]{2}", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"%[0-9A-F]{2}", RegexOptions.Singleline, 100)] + private static partial Regex removePctEncodedCharacters(); public static string SanitizeParameterNameForCodeSymbols(this string original, string replaceEncodedCharactersWith = "") { if (string.IsNullOrEmpty(original)) return original; - return removePctEncodedCharacters.Replace(original.ToCamelCase('-', '.', '~').SanitizeParameterNameForUrlTemplate(), replaceEncodedCharactersWith); + return removePctEncodedCharacters().Replace(original.ToCamelCase('-', '.', '~').SanitizeParameterNameForUrlTemplate(), replaceEncodedCharactersWith); } } diff --git a/src/Kiota.Builder/Extensions/StringExtensions.cs b/src/Kiota.Builder/Extensions/StringExtensions.cs index 00388b3e2b..ad1c39f28d 100644 --- a/src/Kiota.Builder/Extensions/StringExtensions.cs +++ b/src/Kiota.Builder/Extensions/StringExtensions.cs @@ -9,7 +9,7 @@ using System.Threading; namespace Kiota.Builder.Extensions; -public static class StringExtensions +public static partial class StringExtensions { private const int MaxStackLimit = 1024; @@ -149,7 +149,8 @@ public static string ReplaceDotsWithSlashInNamespaces(this string? namespaced) /// /// Cleanup regex that removes all special characters from ASCII 0-127 /// - private static readonly Regex propertyCleanupRegex = new(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Singleline, 100)] + private static partial Regex propertyCleanupRegex(); private const string CleanupGroupName = "followingLetter"; public static string CleanupSymbolName(this string? original) { @@ -157,13 +158,13 @@ public static string CleanupSymbolName(this string? original) string result = NormalizeSymbolsBeforeCleanup(original); - result = propertyCleanupRegex.Replace(result, + result = propertyCleanupRegex().Replace(result, static x => x.Groups.Keys.Contains(CleanupGroupName) ? x.Groups[CleanupGroupName].Value.ToFirstCharacterUpperCase() : string.Empty); //strip out any invalid characters, and replace any following one by its uppercase version if (result.Length != 0 && int.TryParse(result.AsSpan(0, 1), out var _)) // in most languages a number or starting with a number is not a valid symbol name - result = NumbersSpellingRegex.Replace(result, static x => x.Groups["number"] + result = NumbersSpellingRegex().Replace(result, static x => x.Groups["number"] .Value .Select(static x => SpelledOutNumbers[x]) .Aggregate(static (z, y) => z + y)); @@ -180,8 +181,8 @@ public static string CleanupSymbolName(this string? original) return result; } - - private static readonly Regex NumbersSpellingRegex = new(@"^(?\d+)", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"^(?\d+)", RegexOptions.Singleline, 100)] + private static partial Regex NumbersSpellingRegex(); private static readonly Dictionary SpelledOutNumbers = new() { {'0', "Zero"}, {'1', "One"}, diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index cd4c41799a..e8fa656c1c 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -300,10 +300,9 @@ private async Task UpdateLockFile(CancellationToken cancellationToken) await lockManagementService.WriteLockFileAsync(config.OutputPath, configurationLock, cancellationToken).ConfigureAwait(false); } private static readonly GlobComparer globComparer = new(); - [GeneratedRegex(@"([\/\\])\{[\w\d-]+\}([\/\\])", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline, 2000)] - private static partial Regex MultiIndexSameLevelCleanupRegexTemplate(); - private static readonly Regex MultiIndexSameLevelCleanupRegex = MultiIndexSameLevelCleanupRegexTemplate(); - private static string ReplaceAllIndexesWithWildcard(string path, uint depth = 10) => depth == 0 ? path : ReplaceAllIndexesWithWildcard(MultiIndexSameLevelCleanupRegex.Replace(path, "$1{*}$2"), depth - 1); // the bound needs to be greedy to avoid replacing anything else than single path parameters + [GeneratedRegex(@"([\/\\])\{[\w\d-]+\}([\/\\])", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)] + private static partial Regex MultiIndexSameLevelCleanupRegex(); + private static string ReplaceAllIndexesWithWildcard(string path, uint depth = 10) => depth == 0 ? path : ReplaceAllIndexesWithWildcard(MultiIndexSameLevelCleanupRegex().Replace(path, "$1{*}$2"), depth - 1); // the bound needs to be greedy to avoid replacing anything else than single path parameters private static Dictionary> GetFilterPatternsFromConfiguration(HashSet configPatterns) { return configPatterns.Select(static x => diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index 84286899cf..e0c5913ac4 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -196,7 +196,7 @@ parameterType.TypeDefinition is CodeClass parameterTypeClass && } CrawlTree(currentElement, x => UpdateReferencesToDisambiguatedClasses(x, classesToUpdate, suffix)); } - [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase)] + [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] private static partial Regex CapitalizedFirstLetterAfterDot(); private static void FlattenModelsNamespaces(CodeElement currentElement, CodeNamespace modelsNS) { diff --git a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs index 2d06e426d2..bf0026bda6 100644 --- a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs @@ -12,9 +12,6 @@ namespace Kiota.Builder.Writers.Cli; partial class CliCodeMethodWriter : CodeMethodWriter { - private static readonly Regex DelimitedRegex = CliDelimitedRegex(); - private static readonly Regex CamelCaseRegex = CliCamelCaseRegex(); - private static readonly Regex UppercaseRegex = CliUppercaseRegex(); private const string AllParamType = "bool"; private const string AllParamName = "all"; private const string CancellationTokenParamType = "CancellationToken"; @@ -49,7 +46,7 @@ protected override void WriteCommandBuilderBody(CodeMethod codeElement, CodeClas { var classMethods = parentClass.Methods; var name = codeElement.SimpleName; - name = UppercaseRegex.Replace(name, "-$1").TrimStart('-').ToLowerInvariant(); + name = UppercaseRegex().Replace(name, "-$1").TrimStart('-').ToLowerInvariant(); if (codeElement.HttpMethod == null) { @@ -877,17 +874,17 @@ private static string NormalizeToIdentifier(string input) /// private static string NormalizeToOption(string input) { - var result = CamelCaseRegex.Replace(input, "-$1"); + var result = CamelCaseRegex().Replace(input, "-$1"); // 2 passes for cases like "singleValueLegacyExtendedProperty_id" - result = DelimitedRegex.Replace(result, "-$1"); + result = DelimitedRegex().Replace(result, "-$1"); return result.ToLowerInvariant(); } - [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Compiled)] - private static partial Regex CliDelimitedRegex(); - [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Compiled)] - private static partial Regex CliCamelCaseRegex(); - [GeneratedRegex("([A-Z])", RegexOptions.Compiled)] - private static partial Regex CliUppercaseRegex(); + [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Singleline, 100)] + private static partial Regex DelimitedRegex(); + [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Singleline, 100)] + private static partial Regex CamelCaseRegex(); + [GeneratedRegex("([A-Z])", RegexOptions.Singleline, 100)] + private static partial Regex UppercaseRegex(); } diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index b1d10598d9..02693baf95 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -7,7 +7,7 @@ using Kiota.Builder.OrderComparers; namespace Kiota.Builder.Writers.Java; -public class CodeMethodWriter : BaseElementWriter +public partial class CodeMethodWriter : BaseElementWriter { public CodeMethodWriter(JavaConventionService conventionService) : base(conventionService) { } public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer) @@ -145,10 +145,11 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas else writer.WriteLine($"return new {parentClass.Name}();"); } - private static readonly Regex factoryMethodIndexParser = new(@"_(?\d+)", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"_(?\d+)", RegexOptions.Singleline, 100)] + private static partial Regex factoryMethodIndexParser(); private static void WriteFactoryOverloadMethod(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { - if (int.TryParse(factoryMethodIndexParser.Match(codeElement.Name).Groups["idx"].Value, out var currentDiscriminatorPageIndex) && + if (int.TryParse(factoryMethodIndexParser().Match(codeElement.Name).Groups["idx"].Value, out var currentDiscriminatorPageIndex) && codeElement.Parameters.FirstOrDefault() is CodeParameter parameter) { var takeValue = Math.Min(MaxDiscriminatorsPerMethod, parentClass.DiscriminatorInformation.DiscriminatorMappings.Count() - currentDiscriminatorPageIndex * MaxDiscriminatorsPerMethod); diff --git a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs index fb731ef008..8ce6ee9805 100644 --- a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs +++ b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs @@ -9,7 +9,7 @@ using Kiota.Builder.Refiners; namespace Kiota.Builder.Writers.Java; -public class JavaConventionService : CommonLanguageConventionService +public partial class JavaConventionService : CommonLanguageConventionService { internal static string AutoGenerationHeader => "@jakarta.annotation.Generated(\"com.microsoft.kiota\")"; private const string InternalStreamTypeName = "InputStream"; @@ -122,11 +122,12 @@ public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEn writer.WriteLine(DocCommentEnd); } } - private static readonly Regex nonAsciiReplaceRegex = new(@"[^\u0000-\u007F]+", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"[^\u0000-\u007F]+", RegexOptions.None, 100)] + private static partial Regex nonAsciiReplaceRegex(); internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => string.IsNullOrEmpty(originalDescription) ? originalDescription : - nonAsciiReplaceRegex.Replace(originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase).Replace("*/", string.Empty, StringComparison.OrdinalIgnoreCase), string.Empty); + nonAsciiReplaceRegex().Replace(originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase).Replace("*/", string.Empty, StringComparison.OrdinalIgnoreCase), string.Empty); #pragma warning disable CA1822 // Method should be static internal void AddRequestBuilderBody(CodeClass parentClass, string returnType, LanguageWriter writer, string? urlTemplateVarName = default, IEnumerable? pathParameters = default) { diff --git a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs index 66df608cc9..ff583687ab 100644 --- a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs @@ -6,7 +6,7 @@ using Kiota.Builder.Extensions; namespace Kiota.Builder.Writers.Php; -public class CodeEnumWriter : BaseElementWriter +public partial class CodeEnumWriter : BaseElementWriter { public CodeEnumWriter(PhpConventionService conventionService) : base(conventionService) { } @@ -50,10 +50,11 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"public const {GetEnumValueName(enumProperty.Name)} = '{enumProperty.WireName}';"); } } - private static readonly Regex _enumValueNameRegex = new("([A-Z]{1})", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 100)] + private static partial Regex _enumValueNameRegex(); private static string GetEnumValueName(string original) { - return _enumValueNameRegex.Replace(original, "_$1").Trim('_').ToUpperInvariant(); + return _enumValueNameRegex().Replace(original, "_$1").Trim('_').ToUpperInvariant(); } } diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs index f627543291..7541d52f7f 100644 --- a/src/kiota/KiotaHost.cs +++ b/src/kiota/KiotaHost.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Logging; namespace kiota; -public static class KiotaHost +public static partial class KiotaHost { public static RootCommand GetRootCommand() { @@ -315,8 +315,10 @@ private static Option GetManifestOption(string defaultValue) manifestOption.AddAlias("-a"); return manifestOption; } - private static readonly Regex classNameRegex = new(@"^[a-zA-Z_][\w_-]+", RegexOptions.Compiled, Constants.DefaultRegexTimeout); - private static readonly Regex namespaceNameRegex = new(@"^[\w][\w\._-]+", RegexOptions.Compiled, Constants.DefaultRegexTimeout); + [GeneratedRegex(@"^[a-zA-Z_][\w_-]+", RegexOptions.Singleline, 100)] + private static partial Regex classNameRegex(); + [GeneratedRegex(@"^[\w][\w\._-]+", RegexOptions.Singleline, 100)] + private static partial Regex namespaceNameRegex(); private static Command GetGenerateCommand() { var defaultConfiguration = new GenerationConfiguration(); @@ -333,12 +335,12 @@ private static Command GetGenerateCommand() var classOption = new Option("--class-name", () => defaultConfiguration.ClientClassName, "The class name to use for the core client class."); classOption.AddAlias("-c"); classOption.ArgumentHelpName = "name"; - AddStringRegexValidator(classOption, classNameRegex, "class name"); + AddStringRegexValidator(classOption, classNameRegex(), "class name"); var namespaceOption = new Option("--namespace-name", () => defaultConfiguration.ClientNamespaceName, "The namespace to use for the core client class specified with the --class-name option."); namespaceOption.AddAlias("-n"); namespaceOption.ArgumentHelpName = "name"; - AddStringRegexValidator(namespaceOption, namespaceNameRegex, "namespace name"); + AddStringRegexValidator(namespaceOption, namespaceNameRegex(), "namespace name"); var logLevelOption = GetLogLevelOption(); diff --git a/src/kiota/Rpc/Server.cs b/src/kiota/Rpc/Server.cs index 10a6c51aed..97a54d9ae5 100644 --- a/src/kiota/Rpc/Server.cs +++ b/src/kiota/Rpc/Server.cs @@ -17,7 +17,7 @@ using Microsoft.OpenApi.Services; namespace kiota.Rpc; -internal class Server : IServer +internal partial class Server : IServer { protected KiotaConfiguration Configuration { @@ -133,12 +133,13 @@ private static IEnumerable GetOperationsFromTreeNode(OpenApiUrlTreeNode Enumerable.Empty()) .Union(node.Children.SelectMany(static x => GetOperationsFromTreeNode(x.Value))); } - private static readonly Regex indexingNormalizationRegex = new(@"{\w+}", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); + [GeneratedRegex(@"{\w+}", RegexOptions.Singleline, 100)] + private static partial Regex indexingNormalizationRegex(); private static string NormalizeOperationNodePath(OpenApiUrlTreeNode node, OperationType operationType, bool forIndexing = false) { var name = $"{node.Path}#{operationType.ToString().ToUpperInvariant()}"; if (forIndexing) - return indexingNormalizationRegex.Replace(name, "{}"); + return indexingNormalizationRegex().Replace(name, "{}"); return name; } public async Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, CancellationToken cancellationToken) From b2f176200f6170c424b1d15e4b863ac97a57d002 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 11:07:48 -0500 Subject: [PATCH 02/16] - temp: adds regex repro workflow --- .github/workflows/regex-repro.yml | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/regex-repro.yml diff --git a/.github/workflows/regex-repro.yml b/.github/workflows/regex-repro.yml new file mode 100644 index 0000000000..229a4f78d1 --- /dev/null +++ b/.github/workflows/regex-repro.yml @@ -0,0 +1,60 @@ +name: Attempt to reproduce 3797 + +on: + push: + +jobs: + test: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + exec: + [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + ] + fail-fast: false + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.x + - name: Compile the CLI in debug mode + run: | + dotnet restore ./src/kiota + dotnet build ./src/kiota + - name: Run the CLI + run: | + nohup sh -c "for i in 1 2 3 4 5 6 7 8 9 10; do while : ; do : ; done & done" > /dev/null 2> /dev/null & + for ((n=0;n<100;n++)) + do + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/twitter.com/current/2.61/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/notion.com/1.0.0/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/stripe.com/2022-11-15/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://raw.githubusercontent.com/googlemaps/openapi-specification/main/dist/google-maps-platform-openapi3.yml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/meraki.com/0.0.0-streaming/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://developers.pipedrive.com/docs/api/v1/openapi.yaml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/twilio.com/api/1.42.0/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/docusign.net/v2.1/openapi.json" --output=tmp --clean-output --clear-cache --language java + done From 74ec9b46ae60cb2152d3abe7a485f7919daae64a Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 11:35:07 -0500 Subject: [PATCH 03/16] - switches to a lazy matching for vendor cleanup Signed-off-by: Vincent Biret --- src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index 7995564db5..8b1843eda1 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -9,7 +9,7 @@ namespace Kiota.Builder.Extensions; public static partial class OpenApiOperationExtensions { internal static readonly HashSet SuccessCodes = new(StringComparer.OrdinalIgnoreCase) { "200", "201", "202", "203", "206", "2XX" }; //204 excluded as it won't have a schema - [GeneratedRegex(@"[^/]+\+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] + [GeneratedRegex(@"[^/]+?\+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] private static partial Regex vendorSpecificCleanup(); /// /// cleans application/vnd.github.mercy-preview+json to application/json From d513200557c8165a269d1ee8e245b0d70aede922 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 11:40:04 -0500 Subject: [PATCH 04/16] - adds wf disaptch to regex repro Signed-off-by: Vincent Biret --- .github/workflows/regex-repro.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/regex-repro.yml b/.github/workflows/regex-repro.yml index 229a4f78d1..db3dea8e92 100644 --- a/.github/workflows/regex-repro.yml +++ b/.github/workflows/regex-repro.yml @@ -2,6 +2,7 @@ name: Attempt to reproduce 3797 on: push: + workflow_dispatch: jobs: test: From cfe9c4aa58fe07d4af1c9efa64c68efa3be2bfcc Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 12:58:07 -0500 Subject: [PATCH 05/16] - replaces problematic regex with manual implementation Signed-off-by: Vincent Biret --- .../Extensions/OpenApiOperationExtensions.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index 8b1843eda1..c65da5aa9c 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; using Kiota.Builder.Configuration; using Microsoft.OpenApi.Models; @@ -9,8 +8,16 @@ namespace Kiota.Builder.Extensions; public static partial class OpenApiOperationExtensions { internal static readonly HashSet SuccessCodes = new(StringComparer.OrdinalIgnoreCase) { "200", "201", "202", "203", "206", "2XX" }; //204 excluded as it won't have a schema - [GeneratedRegex(@"[^/]+?\+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] - private static partial Regex vendorSpecificCleanup(); + private static string vendorSpecificCleanup(string input) + { + var slashIndex = input.IndexOf('/', StringComparison.OrdinalIgnoreCase); + var plusIndex = input.IndexOf('+', StringComparison.OrdinalIgnoreCase); + if (slashIndex == -1 || plusIndex == -1) + return input; + if (plusIndex < slashIndex) + return input; + return input[0..(slashIndex + 1)] + input[(plusIndex + 1)..]; + } /// /// cleans application/vnd.github.mercy-preview+json to application/json /// @@ -49,7 +56,7 @@ internal static IEnumerable GetValidSchemas(this IDictionary !string.IsNullOrEmpty(c.Key)) .Select(static c => (Key: c.Key.Split(';', StringSplitOptions.RemoveEmptyEntries)[0], c.Value)) - .Where(c => structuredMimeTypes.Contains(c.Key) || structuredMimeTypes.Contains(vendorSpecificCleanup().Replace(c.Key, string.Empty))) + .Where(c => structuredMimeTypes.Contains(c.Key) || structuredMimeTypes.Contains(vendorSpecificCleanup(c.Key))) .Select(static co => co.Value.Schema) .Where(static s => s is not null); } From a4d0128ec5a8af973cf145c689fae1f050d065ee Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 14:27:31 -0500 Subject: [PATCH 06/16] - downloads descriptions before-hand to limit throttling Signed-off-by: Vincent Biret --- .github/workflows/regex-repro.yml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/regex-repro.yml b/.github/workflows/regex-repro.yml index db3dea8e92..1a7b7b000f 100644 --- a/.github/workflows/regex-repro.yml +++ b/.github/workflows/regex-repro.yml @@ -46,16 +46,25 @@ jobs: dotnet build ./src/kiota - name: Run the CLI run: | + curl -o petstore.yaml https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml + curl -o twitter.json https://api.apis.guru/v2/specs/twitter.com/current/2.61/openapi.json + curl -o notion.json https://api.apis.guru/v2/specs/notion.com/1.0.0/openapi.json + curl -o stripe.json https://api.apis.guru/v2/specs/stripe.com/2022-11-15/openapi.json + curl -o maps.yaml https://raw.githubusercontent.com/googlemaps/openapi-specification/main/dist/google-maps-platform-openapi3.yml + curl -o meraki.json https://api.apis.guru/v2/specs/meraki.com/0.0.0-streaming/openapi.json + curl -o pipedrive.yaml https://developers.pipedrive.com/docs/api/v1/openapi.yaml + curl -o twilio.json https://api.apis.guru/v2/specs/twilio.com/api/1.42.0/openapi.json + curl -o docusign.json https://api.apis.guru/v2/specs/docusign.net/v2.1/openapi.json nohup sh -c "for i in 1 2 3 4 5 6 7 8 9 10; do while : ; do : ; done & done" > /dev/null 2> /dev/null & for ((n=0;n<100;n++)) do - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/twitter.com/current/2.61/openapi.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/notion.com/1.0.0/openapi.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/stripe.com/2022-11-15/openapi.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://raw.githubusercontent.com/googlemaps/openapi-specification/main/dist/google-maps-platform-openapi3.yml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/meraki.com/0.0.0-streaming/openapi.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://developers.pipedrive.com/docs/api/v1/openapi.yaml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/twilio.com/api/1.42.0/openapi.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="https://api.apis.guru/v2/specs/docusign.net/v2.1/openapi.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/petstore.yaml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twitter.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/notion.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/stripe.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/maps.yaml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/meraki.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/pipedrive.yaml" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twilio.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/docusign.json" --output=tmp --clean-output --clear-cache --language java done From 38ed9accb9923d225513e9e05e72ec6e73cbc4a2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 14:28:02 -0500 Subject: [PATCH 07/16] - avoids running the regex twice Signed-off-by: Vincent Biret --- src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs index 4f3b65ae21..08007ff72d 100644 --- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -114,9 +114,9 @@ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, Struct { if (stripExtensionForIndexersTestRegex().IsMatch(rawClassName)) rawClassName = stripExtensionForIndexersRegex().Replace(rawClassName, string.Empty); - if ((currentNode?.DoesNodeBelongToItemSubnamespace() ?? false) && idClassNameCleanup().IsMatch(rawClassName)) + if ((currentNode?.DoesNodeBelongToItemSubnamespace() ?? false) && idClassNameCleanup().Replace(rawClassName, string.Empty) is string cleanedUpClassName && !cleanedUpClassName.Equals(rawClassName, StringComparison.Ordinal)) { - rawClassName = idClassNameCleanup().Replace(rawClassName, string.Empty); + rawClassName = cleanedUpClassName; if (WithKeyword.Equals(rawClassName, StringComparison.Ordinal)) // in case the single parameter doesn't follow {classname-id} we get the previous segment rawClassName = currentNode.Path .Split(PathNameSeparator, StringSplitOptions.RemoveEmptyEntries) From d5961fa53e3650e682567c1aa633cfdd850a2db9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 14:28:48 -0500 Subject: [PATCH 08/16] - increases default regex timeout Signed-off-by: Vincent Biret --- .../Extensions/OpenApiUrlTreeNodeExtensions.cs | 16 ++++++++-------- src/Kiota.Builder/Extensions/StringExtensions.cs | 4 ++-- src/Kiota.Builder/Refiners/RubyRefiner.cs | 2 +- .../Writers/CLI/CliCodeMethodWriter.cs | 6 +++--- .../Writers/Java/CodeMethodWriter.cs | 2 +- .../Writers/Java/JavaConventionService.cs | 2 +- src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs | 2 +- src/kiota/KiotaHost.cs | 4 ++-- src/kiota/Rpc/Server.cs | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs index 08007ff72d..f392e6ffc7 100644 --- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -38,10 +38,10 @@ public static string GetNodeNamespaceFromPath(this OpenApiUrlTreeNode currentNod return currentNode.Path.GetNamespaceFromPath(prefix); } //{id}, name(idParam={id}), name(idParam='{id}'), name(idParam='{id}',idParam2='{id2}') - [GeneratedRegex(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Singleline, 200)] private static partial Regex PathParametersRegex(); // microsoft.graph.getRoleScopeTagsByIds(ids=@ids) - [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 200)] private static partial Regex AtSignPathParameterRegex(); private const char RequestParametersChar = '{'; private const char RequestParametersEndChar = '}'; @@ -81,7 +81,7 @@ public static IEnumerable GetPathParametersForCurrentSegment(t return Enumerable.Empty(); } private const char PathNameSeparator = '\\'; - [GeneratedRegex(@"-?id\d?}?$", RegexOptions.Singleline | RegexOptions.IgnoreCase, 100)] + [GeneratedRegex(@"-?id\d?}?$", RegexOptions.Singleline | RegexOptions.IgnoreCase, 200)] private static partial Regex idClassNameCleanup(); /// /// Returns the class name for the node with more or less precision depending on the provided arguments @@ -142,7 +142,7 @@ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, Struct "yml", "txt", }; - [GeneratedRegex(@"[\r\n\t]", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"[\r\n\t]", RegexOptions.Singleline, 200)] private static partial Regex descriptionCleanupRegex(); public static string CleanupDescription(this string? description) => string.IsNullOrEmpty(description) ? string.Empty : descriptionCleanupRegex().Replace(description, string.Empty); public static string GetPathItemDescription(this OpenApiUrlTreeNode currentNode, string label, string? defaultValue = default) @@ -174,9 +174,9 @@ private static bool IsPathSegmentWithNumberOfParameters(this string currentSegme return eval(currentSegment.Where(static x => x == RequestParametersChar)); } - [GeneratedRegex(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 200)] private static partial Regex stripExtensionForIndexersRegex(); // so {param-name}.json is considered as indexer - [GeneratedRegex(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 200)] private static partial Regex stripExtensionForIndexersTestRegex(); // so {param-name}.json is considered as indexer public static bool IsComplexPathMultipleParameters(this OpenApiUrlTreeNode currentNode) => (currentNode?.Segment?.IsPathSegmentWithNumberOfParameters(static x => x.Any()) ?? false) && !currentNode.IsPathSegmentWithSingleSimpleParameter(); @@ -215,7 +215,7 @@ public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode) SanitizePathParameterNamesForUrlTemplate(currentNode.Path.Replace('\\', '/'), pathReservedPathParametersIds) + queryStringParameters; } - [GeneratedRegex(@"{(?[^}]+)}", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"{(?[^}]+)}", RegexOptions.Singleline, 200)] private static partial Regex pathParamMatcher(); private static string SanitizePathParameterNamesForUrlTemplate(string original, HashSet reservedParameterNames) { @@ -236,7 +236,7 @@ public static string SanitizeParameterNameForUrlTemplate(this string original) .Replace(".", "%2E", StringComparison.OrdinalIgnoreCase) .Replace("~", "%7E", StringComparison.OrdinalIgnoreCase);// - . ~ are invalid uri template character but don't get encoded by Uri.EscapeDataString } - [GeneratedRegex(@"%[0-9A-F]{2}", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"%[0-9A-F]{2}", RegexOptions.Singleline, 200)] private static partial Regex removePctEncodedCharacters(); public static string SanitizeParameterNameForCodeSymbols(this string original, string replaceEncodedCharactersWith = "") { diff --git a/src/Kiota.Builder/Extensions/StringExtensions.cs b/src/Kiota.Builder/Extensions/StringExtensions.cs index ad1c39f28d..c9b96fa4be 100644 --- a/src/Kiota.Builder/Extensions/StringExtensions.cs +++ b/src/Kiota.Builder/Extensions/StringExtensions.cs @@ -149,7 +149,7 @@ public static string ReplaceDotsWithSlashInNamespaces(this string? namespaced) /// /// Cleanup regex that removes all special characters from ASCII 0-127 /// - [GeneratedRegex(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Singleline, 200)] private static partial Regex propertyCleanupRegex(); private const string CleanupGroupName = "followingLetter"; public static string CleanupSymbolName(this string? original) @@ -181,7 +181,7 @@ public static string CleanupSymbolName(this string? original) return result; } - [GeneratedRegex(@"^(?\d+)", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"^(?\d+)", RegexOptions.Singleline, 200)] private static partial Regex NumbersSpellingRegex(); private static readonly Dictionary SpelledOutNumbers = new() { {'0', "Zero"}, diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index e0c5913ac4..c149c036db 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -196,7 +196,7 @@ parameterType.TypeDefinition is CodeClass parameterTypeClass && } CrawlTree(currentElement, x => UpdateReferencesToDisambiguatedClasses(x, classesToUpdate, suffix)); } - [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase | RegexOptions.Singleline, 100)] + [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase | RegexOptions.Singleline, 200)] private static partial Regex CapitalizedFirstLetterAfterDot(); private static void FlattenModelsNamespaces(CodeElement currentElement, CodeNamespace modelsNS) { diff --git a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs index bf0026bda6..6db19ff200 100644 --- a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs @@ -881,10 +881,10 @@ private static string NormalizeToOption(string input) return result.ToLowerInvariant(); } - [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Singleline, 100)] + [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Singleline, 200)] private static partial Regex DelimitedRegex(); - [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Singleline, 100)] + [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Singleline, 200)] private static partial Regex CamelCaseRegex(); - [GeneratedRegex("([A-Z])", RegexOptions.Singleline, 100)] + [GeneratedRegex("([A-Z])", RegexOptions.Singleline, 200)] private static partial Regex UppercaseRegex(); } diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index 02693baf95..8711bd64ff 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -145,7 +145,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas else writer.WriteLine($"return new {parentClass.Name}();"); } - [GeneratedRegex(@"_(?\d+)", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"_(?\d+)", RegexOptions.Singleline, 200)] private static partial Regex factoryMethodIndexParser(); private static void WriteFactoryOverloadMethod(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs index 8ce6ee9805..8258d9b438 100644 --- a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs +++ b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs @@ -122,7 +122,7 @@ public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEn writer.WriteLine(DocCommentEnd); } } - [GeneratedRegex(@"[^\u0000-\u007F]+", RegexOptions.None, 100)] + [GeneratedRegex(@"[^\u0000-\u007F]+", RegexOptions.None, 200)] private static partial Regex nonAsciiReplaceRegex(); internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => string.IsNullOrEmpty(originalDescription) ? diff --git a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs index ff583687ab..29a171766c 100644 --- a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs @@ -50,7 +50,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"public const {GetEnumValueName(enumProperty.Name)} = '{enumProperty.WireName}';"); } } - [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 200)] private static partial Regex _enumValueNameRegex(); private static string GetEnumValueName(string original) { diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs index 7541d52f7f..df65ef687b 100644 --- a/src/kiota/KiotaHost.cs +++ b/src/kiota/KiotaHost.cs @@ -315,9 +315,9 @@ private static Option GetManifestOption(string defaultValue) manifestOption.AddAlias("-a"); return manifestOption; } - [GeneratedRegex(@"^[a-zA-Z_][\w_-]+", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"^[a-zA-Z_][\w_-]+", RegexOptions.Singleline, 200)] private static partial Regex classNameRegex(); - [GeneratedRegex(@"^[\w][\w\._-]+", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"^[\w][\w\._-]+", RegexOptions.Singleline, 200)] private static partial Regex namespaceNameRegex(); private static Command GetGenerateCommand() { diff --git a/src/kiota/Rpc/Server.cs b/src/kiota/Rpc/Server.cs index 97a54d9ae5..15f29f1ff9 100644 --- a/src/kiota/Rpc/Server.cs +++ b/src/kiota/Rpc/Server.cs @@ -133,7 +133,7 @@ private static IEnumerable GetOperationsFromTreeNode(OpenApiUrlTreeNode Enumerable.Empty()) .Union(node.Children.SelectMany(static x => GetOperationsFromTreeNode(x.Value))); } - [GeneratedRegex(@"{\w+}", RegexOptions.Singleline, 100)] + [GeneratedRegex(@"{\w+}", RegexOptions.Singleline, 200)] private static partial Regex indexingNormalizationRegex(); private static string NormalizeOperationNodePath(OpenApiUrlTreeNode node, OperationType operationType, bool forIndexing = false) { From 33fd9b4648088b1419ac5d23f2e7297daef4923f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 28 Nov 2023 15:12:54 -0500 Subject: [PATCH 09/16] - another bumps of default timeout Signed-off-by: Vincent Biret --- .../EqualityComparers/OpenApiServerComparer.cs | 2 +- .../Extensions/OpenApiUrlTreeNodeExtensions.cs | 18 +++++++++--------- .../Extensions/StringExtensions.cs | 4 ++-- src/Kiota.Builder/Refiners/RubyRefiner.cs | 2 +- .../Writers/CLI/CliCodeMethodWriter.cs | 6 +++--- .../Writers/Java/CodeMethodWriter.cs | 2 +- .../Writers/Java/JavaConventionService.cs | 2 +- .../Writers/Php/CodeEnumWriter.cs | 2 +- src/kiota/KiotaHost.cs | 4 ++-- src/kiota/Rpc/Server.cs | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs index dca85c9a02..1a2333f79e 100644 --- a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs +++ b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs @@ -8,7 +8,7 @@ namespace Kiota.Builder.EqualityComparers; internal sealed partial class OpenApiServerComparer : IEqualityComparer { - [GeneratedRegex("^https?://", RegexOptions.IgnoreCase | RegexOptions.Compiled, 200)] + [GeneratedRegex("^https?://", RegexOptions.IgnoreCase | RegexOptions.Compiled, 500)] private static partial Regex protocolCleanupRegex(); public bool Equals(OpenApiServer? x, OpenApiServer? y) { diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs index f392e6ffc7..c6ad8bf182 100644 --- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs @@ -13,7 +13,7 @@ public static partial class OpenApiUrlTreeNodeExtensions private static string GetDotIfBothNotNullOfEmpty(string x, string y) => string.IsNullOrEmpty(x) || string.IsNullOrEmpty(y) ? string.Empty : "."; private static readonly Func replaceSingleParameterSegmentByItem = static x => x.IsPathSegmentWithSingleSimpleParameter() ? "item" : x; - private static readonly char[] namespaceNameSplitCharacters = new[] { '.', '-', '$' }; //$ref from OData + private static readonly char[] namespaceNameSplitCharacters = ['.', '-', '$']; //$ref from OData internal static string GetNamespaceFromPath(this string currentPath, string prefix) => prefix + ((currentPath?.Contains(PathNameSeparator, StringComparison.OrdinalIgnoreCase) ?? false) ? @@ -38,10 +38,10 @@ public static string GetNodeNamespaceFromPath(this OpenApiUrlTreeNode currentNod return currentNode.Path.GetNamespaceFromPath(prefix); } //{id}, name(idParam={id}), name(idParam='{id}'), name(idParam='{id}',idParam2='{id2}') - [GeneratedRegex(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"(?:\w+)?=?'?\{(?\w+)\}'?,?", RegexOptions.Singleline, 500)] private static partial Regex PathParametersRegex(); // microsoft.graph.getRoleScopeTagsByIds(ids=@ids) - [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"=@(\w+)", RegexOptions.Singleline, 500)] private static partial Regex AtSignPathParameterRegex(); private const char RequestParametersChar = '{'; private const char RequestParametersEndChar = '}'; @@ -81,7 +81,7 @@ public static IEnumerable GetPathParametersForCurrentSegment(t return Enumerable.Empty(); } private const char PathNameSeparator = '\\'; - [GeneratedRegex(@"-?id\d?}?$", RegexOptions.Singleline | RegexOptions.IgnoreCase, 200)] + [GeneratedRegex(@"-?id\d?}?$", RegexOptions.Singleline | RegexOptions.IgnoreCase, 500)] private static partial Regex idClassNameCleanup(); /// /// Returns the class name for the node with more or less precision depending on the provided arguments @@ -142,7 +142,7 @@ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, Struct "yml", "txt", }; - [GeneratedRegex(@"[\r\n\t]", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"[\r\n\t]", RegexOptions.Singleline, 500)] private static partial Regex descriptionCleanupRegex(); public static string CleanupDescription(this string? description) => string.IsNullOrEmpty(description) ? string.Empty : descriptionCleanupRegex().Replace(description, string.Empty); public static string GetPathItemDescription(this OpenApiUrlTreeNode currentNode, string label, string? defaultValue = default) @@ -174,9 +174,9 @@ private static bool IsPathSegmentWithNumberOfParameters(this string currentSegme return eval(currentSegment.Where(static x => x == RequestParametersChar)); } - [GeneratedRegex(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 500)] private static partial Regex stripExtensionForIndexersRegex(); // so {param-name}.json is considered as indexer - [GeneratedRegex(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"\{\w+\}\.(?:json|yaml|yml|csv|txt)$", RegexOptions.Singleline, 500)] private static partial Regex stripExtensionForIndexersTestRegex(); // so {param-name}.json is considered as indexer public static bool IsComplexPathMultipleParameters(this OpenApiUrlTreeNode currentNode) => (currentNode?.Segment?.IsPathSegmentWithNumberOfParameters(static x => x.Any()) ?? false) && !currentNode.IsPathSegmentWithSingleSimpleParameter(); @@ -215,7 +215,7 @@ public static string GetUrlTemplate(this OpenApiUrlTreeNode currentNode) SanitizePathParameterNamesForUrlTemplate(currentNode.Path.Replace('\\', '/'), pathReservedPathParametersIds) + queryStringParameters; } - [GeneratedRegex(@"{(?[^}]+)}", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"{(?[^}]+)}", RegexOptions.Singleline, 500)] private static partial Regex pathParamMatcher(); private static string SanitizePathParameterNamesForUrlTemplate(string original, HashSet reservedParameterNames) { @@ -236,7 +236,7 @@ public static string SanitizeParameterNameForUrlTemplate(this string original) .Replace(".", "%2E", StringComparison.OrdinalIgnoreCase) .Replace("~", "%7E", StringComparison.OrdinalIgnoreCase);// - . ~ are invalid uri template character but don't get encoded by Uri.EscapeDataString } - [GeneratedRegex(@"%[0-9A-F]{2}", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"%[0-9A-F]{2}", RegexOptions.Singleline, 500)] private static partial Regex removePctEncodedCharacters(); public static string SanitizeParameterNameForCodeSymbols(this string original, string replaceEncodedCharactersWith = "") { diff --git a/src/Kiota.Builder/Extensions/StringExtensions.cs b/src/Kiota.Builder/Extensions/StringExtensions.cs index c9b96fa4be..8266834bcd 100644 --- a/src/Kiota.Builder/Extensions/StringExtensions.cs +++ b/src/Kiota.Builder/Extensions/StringExtensions.cs @@ -149,7 +149,7 @@ public static string ReplaceDotsWithSlashInNamespaces(this string? namespaced) /// /// Cleanup regex that removes all special characters from ASCII 0-127 /// - [GeneratedRegex(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"[""\s!#$%&'()*,./:;<=>?@\[\]\\^`’{}|~-](?\w)?", RegexOptions.Singleline, 500)] private static partial Regex propertyCleanupRegex(); private const string CleanupGroupName = "followingLetter"; public static string CleanupSymbolName(this string? original) @@ -181,7 +181,7 @@ public static string CleanupSymbolName(this string? original) return result; } - [GeneratedRegex(@"^(?\d+)", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"^(?\d+)", RegexOptions.Singleline, 500)] private static partial Regex NumbersSpellingRegex(); private static readonly Dictionary SpelledOutNumbers = new() { {'0', "Zero"}, diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index c149c036db..70cc37070f 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -196,7 +196,7 @@ parameterType.TypeDefinition is CodeClass parameterTypeClass && } CrawlTree(currentElement, x => UpdateReferencesToDisambiguatedClasses(x, classesToUpdate, suffix)); } - [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase | RegexOptions.Singleline, 200)] + [GeneratedRegex(@"\\.(\\w)", RegexOptions.IgnoreCase | RegexOptions.Singleline, 500)] private static partial Regex CapitalizedFirstLetterAfterDot(); private static void FlattenModelsNamespaces(CodeElement currentElement, CodeNamespace modelsNS) { diff --git a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs index 6db19ff200..dc9c76c3fc 100644 --- a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs @@ -881,10 +881,10 @@ private static string NormalizeToOption(string input) return result.ToLowerInvariant(); } - [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Singleline, 200)] + [GeneratedRegex("(?<=[a-z])[-_\\.]+([A-Za-z])", RegexOptions.Singleline, 500)] private static partial Regex DelimitedRegex(); - [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Singleline, 200)] + [GeneratedRegex("(?<=[a-z])([A-Z])", RegexOptions.Singleline, 500)] private static partial Regex CamelCaseRegex(); - [GeneratedRegex("([A-Z])", RegexOptions.Singleline, 200)] + [GeneratedRegex("([A-Z])", RegexOptions.Singleline, 500)] private static partial Regex UppercaseRegex(); } diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index 8711bd64ff..e736e15248 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -145,7 +145,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas else writer.WriteLine($"return new {parentClass.Name}();"); } - [GeneratedRegex(@"_(?\d+)", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"_(?\d+)", RegexOptions.Singleline, 500)] private static partial Regex factoryMethodIndexParser(); private static void WriteFactoryOverloadMethod(CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs index 8258d9b438..7d7d749cad 100644 --- a/src/Kiota.Builder/Writers/Java/JavaConventionService.cs +++ b/src/Kiota.Builder/Writers/Java/JavaConventionService.cs @@ -122,7 +122,7 @@ public void WriteLongDescription(CodeElement element, LanguageWriter writer, IEn writer.WriteLine(DocCommentEnd); } } - [GeneratedRegex(@"[^\u0000-\u007F]+", RegexOptions.None, 200)] + [GeneratedRegex(@"[^\u0000-\u007F]+", RegexOptions.None, 500)] private static partial Regex nonAsciiReplaceRegex(); internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => string.IsNullOrEmpty(originalDescription) ? diff --git a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs index 29a171766c..b85e876273 100644 --- a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs @@ -50,7 +50,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine($"public const {GetEnumValueName(enumProperty.Name)} = '{enumProperty.WireName}';"); } } - [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 500)] private static partial Regex _enumValueNameRegex(); private static string GetEnumValueName(string original) { diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs index df65ef687b..d62b428369 100644 --- a/src/kiota/KiotaHost.cs +++ b/src/kiota/KiotaHost.cs @@ -315,9 +315,9 @@ private static Option GetManifestOption(string defaultValue) manifestOption.AddAlias("-a"); return manifestOption; } - [GeneratedRegex(@"^[a-zA-Z_][\w_-]+", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"^[a-zA-Z_][\w_-]+", RegexOptions.Singleline, 500)] private static partial Regex classNameRegex(); - [GeneratedRegex(@"^[\w][\w\._-]+", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"^[\w][\w\._-]+", RegexOptions.Singleline, 500)] private static partial Regex namespaceNameRegex(); private static Command GetGenerateCommand() { diff --git a/src/kiota/Rpc/Server.cs b/src/kiota/Rpc/Server.cs index 15f29f1ff9..1db32d1ecc 100644 --- a/src/kiota/Rpc/Server.cs +++ b/src/kiota/Rpc/Server.cs @@ -133,7 +133,7 @@ private static IEnumerable GetOperationsFromTreeNode(OpenApiUrlTreeNode Enumerable.Empty()) .Union(node.Children.SelectMany(static x => GetOperationsFromTreeNode(x.Value))); } - [GeneratedRegex(@"{\w+}", RegexOptions.Singleline, 200)] + [GeneratedRegex(@"{\w+}", RegexOptions.Singleline, 500)] private static partial Regex indexingNormalizationRegex(); private static string NormalizeOperationNodePath(OpenApiUrlTreeNode node, OperationType operationType, bool forIndexing = false) { From 7c5a5b7479251c77c13a5afaef835a6558845726 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 09:33:29 -0500 Subject: [PATCH 10/16] - fixes concurrency issue with inheritance index Signed-off-by: Vincent Biret --- src/Kiota.Builder/KiotaBuilder.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index e8fa656c1c..af0c2f02db 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -2033,23 +2033,23 @@ private void TrimInheritedModels() foreach (var leafNamespace in FindLeafNamespaces(modelsNamespace)) RemoveEmptyNamespaces(leafNamespace, modelsNamespace); } - private ConcurrentDictionary> GetDerivationIndex(IEnumerable models) + private ConcurrentDictionary> GetDerivationIndex(IEnumerable models) { - var result = new ConcurrentDictionary>(); + var result = new ConcurrentDictionary>(); Parallel.ForEach(models, parallelOptions, x => { - if (x.BaseClass is CodeClass parentClass && !result.TryAdd(parentClass, new() { x })) + if (x.BaseClass is CodeClass parentClass && !result.TryAdd(parentClass, [x])) result[parentClass].Add(x); }); return result; } - private ConcurrentDictionary> GetInheritanceIndex(ConcurrentDictionary> derivedIndex) + private ConcurrentDictionary> GetInheritanceIndex(ConcurrentDictionary> derivedIndex) { - var result = new ConcurrentDictionary>(); + var result = new ConcurrentDictionary>(); Parallel.ForEach(derivedIndex, parallelOptions, entry => { foreach (var derivedClass in entry.Value) - if (!result.TryAdd(derivedClass, new() { entry.Key })) + if (!result.TryAdd(derivedClass, [entry.Key])) result[derivedClass].Add(entry.Key); }); return result; @@ -2069,12 +2069,12 @@ private static void RemoveEmptyNamespaces(CodeNamespace currentNamespace, CodeNa parentNamespace.RemoveChildElement(currentNamespace); RemoveEmptyNamespaces(parentNamespace, stopAtNamespace); } - private static IEnumerable GetDerivedDefinitions(ConcurrentDictionary> models, CodeClass[] modelsInUse) + private static IEnumerable GetDerivedDefinitions(ConcurrentDictionary> models, CodeClass[] modelsInUse) { var currentDerived = modelsInUse.SelectMany(x => models.TryGetValue(x, out var res) ? res : Enumerable.Empty()).ToArray(); - return currentDerived.Union(currentDerived.SelectMany(x => GetDerivedDefinitions(models, new CodeClass[] { x }))); + return currentDerived.Union(currentDerived.SelectMany(x => GetDerivedDefinitions(models, [x]))); } - private static IEnumerable GetRelatedDefinitions(CodeElement currentElement, ConcurrentDictionary> derivedIndex, ConcurrentDictionary> inheritanceIndex, ConcurrentDictionary? visited = null) + private static IEnumerable GetRelatedDefinitions(CodeElement currentElement, ConcurrentDictionary> derivedIndex, ConcurrentDictionary> inheritanceIndex, ConcurrentDictionary? visited = null) { visited ??= new(); if (currentElement is not CodeClass currentClass || !visited.TryAdd(currentClass, true)) return Enumerable.Empty(); @@ -2084,7 +2084,7 @@ private static IEnumerable GetRelatedDefinitions(CodeElement curren .Where(static x => x is CodeClass || x is CodeEnum) .SelectMany(x => x is CodeClass classDefinition ? (inheritanceIndex.TryGetValue(classDefinition, out var res) ? res : Enumerable.Empty()) - .Union(GetDerivedDefinitions(derivedIndex, new CodeClass[] { classDefinition })) + .Union(GetDerivedDefinitions(derivedIndex, [classDefinition])) .Union(new[] { classDefinition }) .OfType() : new[] { x }) From 71962a76d6aa8af33d33e38f793b8c5ee6cfe2a5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 09:34:32 -0500 Subject: [PATCH 11/16] - disables validation rules to reduce log verbosity Signed-off-by: Vincent Biret --- .github/workflows/regex-repro.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/regex-repro.yml b/.github/workflows/regex-repro.yml index 1a7b7b000f..957e5e2a24 100644 --- a/.github/workflows/regex-repro.yml +++ b/.github/workflows/regex-repro.yml @@ -58,13 +58,13 @@ jobs: nohup sh -c "for i in 1 2 3 4 5 6 7 8 9 10; do while : ; do : ; done & done" > /dev/null 2> /dev/null & for ((n=0;n<100;n++)) do - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/petstore.yaml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twitter.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/notion.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/stripe.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/maps.yaml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/meraki.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/pipedrive.yaml" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twilio.json" --output=tmp --clean-output --clear-cache --language java - src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/docusign.json" --output=tmp --clean-output --clear-cache --language java + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/petstore.yaml" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twitter.json" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/notion.json" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/stripe.json" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/maps.yaml" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/meraki.json" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/pipedrive.yaml" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/twilio.json" --output=tmp --clean-output --clear-cache --language java --dvr all + src/kiota/bin/Debug/net8.0/kiota generate --openapi="$(pwd)/docusign.json" --output=tmp --clean-output --clear-cache --language java --dvr all done From 02e5698fcbb020cc6f53fd7d08e039c1292f0d4f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 09:55:34 -0500 Subject: [PATCH 12/16] - fixes null ref exception in types trimming --- src/Kiota.Builder/CodeDOM/CodeBlock.cs | 2 +- src/Kiota.Builder/CodeDOM/ICodeElement.cs | 1 + src/Kiota.Builder/KiotaBuilder.cs | 17 +++++++++-------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Kiota.Builder/CodeDOM/CodeBlock.cs b/src/Kiota.Builder/CodeDOM/CodeBlock.cs index 9b9ad01bfe..6a7e80c9cb 100644 --- a/src/Kiota.Builder/CodeDOM/CodeBlock.cs +++ b/src/Kiota.Builder/CodeDOM/CodeBlock.cs @@ -39,7 +39,7 @@ public virtual void RenameChildElement(string oldName, string newName) } else throw new InvalidOperationException($"The element to rename was not found {oldName}"); } - public void RemoveChildElement(params T[] elements) where T : CodeElement + public void RemoveChildElement(params T[] elements) where T : ICodeElement { if (elements == null) return; RemoveChildElementByName(elements.Select(static x => x.Name).ToArray()); diff --git a/src/Kiota.Builder/CodeDOM/ICodeElement.cs b/src/Kiota.Builder/CodeDOM/ICodeElement.cs index 671cd8dbe4..4cbfd90c4b 100644 --- a/src/Kiota.Builder/CodeDOM/ICodeElement.cs +++ b/src/Kiota.Builder/CodeDOM/ICodeElement.cs @@ -9,4 +9,5 @@ string Name { get; set; } + T GetImmediateParentOfType(CodeElement? item = null); } diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index af0c2f02db..376242ffe9 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -1991,12 +1991,12 @@ private IEnumerable> GetDiscriminatorMappings(Ope .Where(static x => x.Value != null) .Select(static x => KeyValuePair.Create(x.Key, x.Value!)); } - private static IEnumerable GetAllModels(CodeNamespace currentNamespace) + private static IEnumerable GetAllModels(CodeNamespace currentNamespace) { var classes = currentNamespace.Classes.ToArray(); return classes.Union(classes.SelectMany(GetAllInnerClasses)) .Where(static x => x.IsOfKind(CodeClassKind.Model)) - .OfType() + .OfType() .Union(currentNamespace.Enums) .Union(currentNamespace.Namespaces.SelectMany(static x => GetAllModels(x))); } @@ -2016,7 +2016,7 @@ private void TrimInheritedModels() var classesInUse = derivedClassesInUse.Union(classesDirectlyInUse).Union(baseOfModelsInUse).ToHashSet(); var reusableClassesDerivationIndex = GetDerivationIndex(reusableModels.OfType()); var reusableClassesInheritanceIndex = GetInheritanceIndex(allModelClassesIndex); - var relatedModels = classesInUse.SelectMany(x => GetRelatedDefinitions(x, reusableClassesDerivationIndex, reusableClassesInheritanceIndex)).Union(modelsDirectlyInUse.Where(x => x is CodeEnum)).ToHashSet();// re-including models directly in use for enums + var relatedModels = classesInUse.SelectMany(x => GetRelatedDefinitions(x, reusableClassesDerivationIndex, reusableClassesInheritanceIndex)).Union(modelsDirectlyInUse.OfType()).ToHashSet();// re-including models directly in use for enums Parallel.ForEach(reusableModels, parallelOptions, x => { if (relatedModels.Contains(x) || classesInUse.Contains(x)) return; @@ -2074,23 +2074,24 @@ private static IEnumerable GetDerivedDefinitions(ConcurrentDictionary var currentDerived = modelsInUse.SelectMany(x => models.TryGetValue(x, out var res) ? res : Enumerable.Empty()).ToArray(); return currentDerived.Union(currentDerived.SelectMany(x => GetDerivedDefinitions(models, [x]))); } - private static IEnumerable GetRelatedDefinitions(CodeElement currentElement, ConcurrentDictionary> derivedIndex, ConcurrentDictionary> inheritanceIndex, ConcurrentDictionary? visited = null) + private static IEnumerable GetRelatedDefinitions(ITypeDefinition currentElement, ConcurrentDictionary> derivedIndex, ConcurrentDictionary> inheritanceIndex, ConcurrentDictionary? visited = null) { visited ??= new(); - if (currentElement is not CodeClass currentClass || !visited.TryAdd(currentClass, true)) return Enumerable.Empty(); + if (currentElement is not CodeClass currentClass || !visited.TryAdd(currentClass, true)) return Enumerable.Empty(); var propertiesDefinitions = currentClass.Properties .SelectMany(static x => x.Type.AllTypes) - .Select(static x => x.TypeDefinition!) + .Select(static x => x.TypeDefinition) + .OfType() .Where(static x => x is CodeClass || x is CodeEnum) .SelectMany(x => x is CodeClass classDefinition ? (inheritanceIndex.TryGetValue(classDefinition, out var res) ? res : Enumerable.Empty()) .Union(GetDerivedDefinitions(derivedIndex, [classDefinition])) .Union(new[] { classDefinition }) - .OfType() : + .OfType() : new[] { x }) .Distinct() .ToArray(); - var propertiesParentTypes = propertiesDefinitions.OfType().SelectMany(static x => x.GetInheritanceTree(false, false)).ToArray(); + var propertiesParentTypes = propertiesDefinitions.OfType().SelectMany(static x => x.GetInheritanceTree(false, false)).OfType().ToArray(); return propertiesDefinitions .Union(propertiesParentTypes) .Union(propertiesParentTypes.SelectMany(x => GetRelatedDefinitions(x, derivedIndex, inheritanceIndex, visited))) From c784b4912b2e5e7c18bf4854930d49a46cac88fb Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 12:41:22 -0500 Subject: [PATCH 13/16] - cleans up the load testing workflow Signed-off-by: Vincent Biret --- .github/workflows/{regex-repro.yml => load-tests.yml} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename .github/workflows/{regex-repro.yml => load-tests.yml} (97%) diff --git a/.github/workflows/regex-repro.yml b/.github/workflows/load-tests.yml similarity index 97% rename from .github/workflows/regex-repro.yml rename to .github/workflows/load-tests.yml index 957e5e2a24..295c8d0db2 100644 --- a/.github/workflows/regex-repro.yml +++ b/.github/workflows/load-tests.yml @@ -1,8 +1,9 @@ -name: Attempt to reproduce 3797 +name: Generation load tests on: - push: workflow_dispatch: + schedule: + - cron: "0 4 * * 1" # every monday at 3am UTC jobs: test: From 49324344837e3c83d98fb694ac7c071844874bfa Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 12:42:08 -0500 Subject: [PATCH 14/16] - code linting Signed-off-by: Vincent Biret --- src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index c65da5aa9c..6d14c22441 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.OpenApi.Models; namespace Kiota.Builder.Extensions; -public static partial class OpenApiOperationExtensions +public static class OpenApiOperationExtensions { internal static readonly HashSet SuccessCodes = new(StringComparer.OrdinalIgnoreCase) { "200", "201", "202", "203", "206", "2XX" }; //204 excluded as it won't have a schema private static string vendorSpecificCleanup(string input) From cf8b1e80cb34a1896a515a0b897e49dde7284126 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 29 Nov 2023 12:43:38 -0500 Subject: [PATCH 15/16] - adds changelog entry fro regex perf fix Signed-off-by: Vincent Biret --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8ec88e76..e495928c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a bug where path parameters deduplication would create collisions on sub path segments. [#3757](https://github.com/microsoft/kiota/issues/3757) - Moved from net7 to net8. - Removed windows OS from docker multi-partform image to align with [dotnet changes](https://github.com/dotnet/dotnet-docker/issues/4492). -- Fixed a bug where import statements for additionalDataHolder and enumSet are missing when BackingStore is enabled in java. [#3643](https://github.com/microsoft/kiota/pull/3643) +- Fixed a bug where import statements for additionalDataHolder and enumSet are missing when BackingStore is enabled in java. [#3643](https://github.com/microsoft/kiota/pull/3643) +- Fixed an issue where Kiota's regex's might time out. [#3797](https://github.com/microsoft/kiota/issues/3797) - Fixed a bug where getBackingStore method body was malformed for java. [#3643](https://github.com/microsoft/kiota/pull/3643) - Fixed a bug where serialize method will not write additional data when backingStore is enabled for java. [#3643](https://github.com/microsoft/kiota/pull/3643) - Fixed a bug where paths with parameters in the same position but different names would make generation fail. [#3756](https://github.com/microsoft/kiota/issues/3756) From 29bba26ee6b305abcc30629c75a36a5b57256ad4 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 30 Nov 2023 05:15:30 -0500 Subject: [PATCH 16/16] Update src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs Co-authored-by: Eastman --- src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs index 1a2333f79e..14a6b7be52 100644 --- a/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs +++ b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs @@ -8,7 +8,7 @@ namespace Kiota.Builder.EqualityComparers; internal sealed partial class OpenApiServerComparer : IEqualityComparer { - [GeneratedRegex("^https?://", RegexOptions.IgnoreCase | RegexOptions.Compiled, 500)] + [GeneratedRegex("^https?://", RegexOptions.IgnoreCase, 500)] private static partial Regex protocolCleanupRegex(); public bool Equals(OpenApiServer? x, OpenApiServer? y) {