Skip to content

Commit

Permalink
chore: remove Linq usage. (#189)
Browse files Browse the repository at this point in the history
* chore: remove Linq usage.

* Update src/Microsoft.Kiota.Cli.Commons/IO/ODataPagingService.cs

Co-authored-by: Vincent Biret <vibiret@microsoft.com>

* Update src/Microsoft.Kiota.Cli.Commons/IO/TableOutputFormatter.cs

Co-authored-by: Vincent Biret <vibiret@microsoft.com>

---------

Co-authored-by: Vincent Biret <vibiret@microsoft.com>
  • Loading branch information
calebkiage and baywet authored Jul 25, 2024
1 parent 63c766a commit faef688
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ public async Task Return_Right_On_Null_Data_In_Left_Stream()
}

[Theory]
[InlineData(null, "[20,21,24]", "[30]", "[20,21,24,30]")]
[InlineData("", "[20,21,24]", "[30]", "[20,21,24,30]")]
[InlineData("value", "{\"value\": [20]}", "{\"value\": [30]}", "{\"value\":[20,30]}")]
[InlineData(null, "[20,21,24]", "[30,32]", "[20,21,24,30,32]")]

Check warning on line 122 in src/Microsoft.Kiota.Cli.Commons.Tests/IO/ODataPagingServiceTest.cs

View workflow job for this annotation

GitHub Actions / Analyze

Null should not be used for type parameter 'itemName' of type 'string'. Use a non-null value, or convert the parameter to a nullable type. (https://xunit.net/xunit.analyzers/rules/xUnit1012)

Check warning on line 122 in src/Microsoft.Kiota.Cli.Commons.Tests/IO/ODataPagingServiceTest.cs

View workflow job for this annotation

GitHub Actions / Analyze

Null should not be used for type parameter 'itemName' of type 'string'. Use a non-null value, or convert the parameter to a nullable type. (https://xunit.net/xunit.analyzers/rules/xUnit1012)

Check warning on line 122 in src/Microsoft.Kiota.Cli.Commons.Tests/IO/ODataPagingServiceTest.cs

View workflow job for this annotation

GitHub Actions / build

Null should not be used for type parameter 'itemName' of type 'string'. Use a non-null value, or convert the parameter to a nullable type. (https://xunit.net/xunit.analyzers/rules/xUnit1012)

Check warning on line 122 in src/Microsoft.Kiota.Cli.Commons.Tests/IO/ODataPagingServiceTest.cs

View workflow job for this annotation

GitHub Actions / build

Null should not be used for type parameter 'itemName' of type 'string'. Use a non-null value, or convert the parameter to a nullable type. (https://xunit.net/xunit.analyzers/rules/xUnit1012)
[InlineData("", "[20,21,24]", "[30,32]", "[20,21,24,30,32]")]
[InlineData("value", "{\"value\": [20,21]}", "{\"value\": [30,32]}", "{\"value\":[20,21,30,32]}")]
[InlineData("value", "{\"value\": [{\"a\": 1}, {\"a\": 2}]}", "{\"value\": [{\"b\": 4}]}", "{\"value\":[{\"a\":1},{\"a\":2},{\"b\":4}]}")]
public async Task Return_Merged_Stream(string itemName, string left, string right, string expected)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Kiota.Cli.Commons.Http.Headers;

Expand Down Expand Up @@ -43,12 +42,12 @@ public sealed class InMemoryHeadersStore : BaseHeadersStore
public bool IsConcurrent { get; }

/// <inheritdoc />
public override IEnumerable<KeyValuePair<string, ICollection<string>>> GetHeaders() => _headers.AsEnumerable();
public override IEnumerable<KeyValuePair<string, ICollection<string>>> GetHeaders() => _headers;

/// <inheritdoc />
public override IEnumerable<KeyValuePair<string, ICollection<string>>> Drain()
{
var existing = _headers.ToList();
var existing = new List<KeyValuePair<string, ICollection<string>>>(_headers);
_headers.Clear();
return existing;
}
Expand Down
57 changes: 45 additions & 12 deletions src/Microsoft.Kiota.Cli.Commons/IO/ODataPagingService.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading;
Expand Down Expand Up @@ -64,7 +63,22 @@ public override bool OnBeforeGetPagedData(PageLinkData pageLinkData, bool fetchA

private static bool IsJson(PageLinkData pageLinkData)
{
return pageLinkData.ResponseContentHeaders.TryGetValue("Content-Type", out var contentType) && contentType.Any(c => c.Contains("json"));

return pageLinkData.ResponseContentHeaders.TryGetValue("Content-Type", out var contentTypes) && HasJsonContentType(contentTypes);
}

private static bool HasJsonContentType(IEnumerable<string> contentTypes)
{
foreach (var contentType in contentTypes)

Check warning on line 72 in src/Microsoft.Kiota.Cli.Commons/IO/ODataPagingService.cs

View workflow job for this annotation

GitHub Actions / Build

Loops should be simplified using the "Where" LINQ method (https://rules.sonarsource.com/csharp/RSPEC-3267)
{
if (contentType.Contains("json", StringComparison.OrdinalIgnoreCase))

{
return true;
}
}

return false;
}

/// <summary>
Expand All @@ -84,9 +98,11 @@ private static bool IsJson(PageLinkData pageLinkData)
return left ?? right;
}

JsonNode? nodeLeft = JsonNode.Parse(left);
var taskLeft = JsonNode.ParseAsync(left, cancellationToken: cancellationToken);
var taskRight = JsonNode.ParseAsync(right, cancellationToken: cancellationToken);
var nodeLeft = await taskLeft;
var nodeRight = await taskRight;
if (left.CanSeek) left.Seek(0, SeekOrigin.Begin);
JsonNode? nodeRight = JsonNode.Parse(right);
if (right.CanSeek) right.Seek(0, SeekOrigin.Begin);

JsonArray? leftArray = null;
Expand Down Expand Up @@ -114,13 +130,28 @@ private static bool IsJson(PageLinkData pageLinkData)

if (leftArray != null && rightArray != null)
{
var elements = rightArray.Where(i => i != null);
var item = elements.FirstOrDefault();
while (item != null)
var enumerator = rightArray.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var node = enumerator.Current;
if (node == null) continue;
if (rightArray.Remove(node))
{
leftArray.Add(node);
enumerator.Dispose();
enumerator = rightArray.GetEnumerator();
}
else
{
throw new InvalidOperationException("Failed to modify a JSON stream.");
}
}
}
finally
{
rightArray.Remove(item);
leftArray.Add(item);
item = elements.FirstOrDefault();
enumerator.Dispose();

Check warning on line 154 in src/Microsoft.Kiota.Cli.Commons/IO/ODataPagingService.cs

View workflow job for this annotation

GitHub Actions / Build

Resource 'enumerator' has already been disposed explicitly or through a using statement implicitly. Remove the redundant disposal. (https://rules.sonarsource.com/csharp/RSPEC-3966)
}
}
if (!string.IsNullOrWhiteSpace(itemName) && nodeLeft != null)
Expand All @@ -137,7 +168,9 @@ private static bool IsJson(PageLinkData pageLinkData)
{
var obj1 = nodeLeft as JsonObject;
if (obj1?[nextLinkName] != null)
{
obj1.Remove(nextLinkName);
}
if (nodeRight is JsonObject obj2 && obj2?[nextLinkName] != null)
{
var nextLink = obj2[nextLinkName];
Expand All @@ -146,7 +179,7 @@ private static bool IsJson(PageLinkData pageLinkData)
}
}
var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
await using var writer = new Utf8JsonWriter(stream);
nodeLeft?.WriteTo(writer);
await writer.FlushAsync(cancellationToken);
stream.Position = 0;
Expand Down
81 changes: 29 additions & 52 deletions src/Microsoft.Kiota.Cli.Commons/IO/TableOutputFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -16,6 +15,7 @@ namespace Microsoft.Kiota.Cli.Commons.IO;
public class TableOutputFormatter : IOutputFormatter
{
private readonly IAnsiConsole _ansiConsole;
private const string CellValueIfMissing = "-";

/// <summary>
/// Creates a new table output formatter with a default console
Expand Down Expand Up @@ -53,7 +53,7 @@ internal Table ConstructTable(JsonDocument document) {
var root = GetRootElement(document.RootElement);
var firstElement = GetFirstElement(root);

IEnumerable<string> propertyNames = GetPropertyNames(firstElement);
List<string> propertyNames = [..GetPropertyNames(firstElement)];
var table = new Table();
table.Expand();

Expand Down Expand Up @@ -100,78 +100,55 @@ private static JsonElement GetRootElement(JsonElement input) {

private static JsonElement GetFirstElement(JsonElement root) {
var firstElement = root;
if (root.ValueKind == JsonValueKind.Array && root.GetArrayLength() > 0)
if (root.ValueKind != JsonValueKind.Array || root.GetArrayLength() <= 0) return firstElement;
var enumerated = root.EnumerateArray();
if (enumerated.MoveNext())
{
var enumerated = root.EnumerateArray();
firstElement = enumerated.FirstOrDefault();
firstElement = enumerated.Current;
}

return firstElement;
}

private static IEnumerable<string> GetPropertyNames(JsonElement firstElement) {
IEnumerable<string> propertyNames;
if (firstElement.ValueKind != JsonValueKind.Object)
{
propertyNames = new List<string> { "Value" };
yield return "Value";
}
else
{
var restrictedValueKinds = new JsonValueKind[] {
JsonValueKind.Array,
JsonValueKind.Object
};
var objectEnumerator = firstElement.EnumerateObject();
var buffer = new List<string>();
foreach (var property in objectEnumerator)
foreach (var property in firstElement.EnumerateObject())
{
if (restrictedValueKinds.Contains(property.Value.ValueKind)) {
continue;
}

buffer.Add(property.Name);
if (property.Value.ValueKind is JsonValueKind.Array or JsonValueKind.Object) continue;
yield return property.Name;
}
propertyNames = buffer;
}

return propertyNames;
}

private static IEnumerable<IRenderable> GetRowColumns(IEnumerable<string> propertyNames, JsonElement row)
{
return propertyNames.Select(p =>
foreach (var columnName in propertyNames)
{
var propertyName = p;
if (row.ValueKind == JsonValueKind.Object)
{
var hasProp = row.TryGetProperty(propertyName, out var property);
if (hasProp)
return GetPropertyValue(property);
else
return new Markup("-");
}
return GetPropertyValue(row);
});
yield return RenderCell(columnName, row);
}
}

private static Markup RenderCell(string columnName, JsonElement row)
{
if (row.ValueKind != JsonValueKind.Object) return GetPropertyValue(row);
var hasProp = row.TryGetProperty(columnName, out var property);
return hasProp ? GetPropertyValue(property) : new Markup(CellValueIfMissing);
}

private static IRenderable GetPropertyValue(JsonElement property)
private static Markup GetPropertyValue(JsonElement property)
{
var valueKind = property.ValueKind;
object? value = null;
switch (valueKind)
return valueKind switch
{
case JsonValueKind.String:
value = property.GetString();
break;
case JsonValueKind.True:
case JsonValueKind.False:
value = property.GetBoolean();
break;
case JsonValueKind.Number:
value = property.GetDecimal();
break;
}
return new Markup(value?.ToString() ?? "-");
JsonValueKind.String => new Markup(property.GetString() ?? CellValueIfMissing),
JsonValueKind.True or JsonValueKind.False => new Markup(property.GetBoolean().ToString()),
JsonValueKind.Number => new Markup(property.GetDecimal().ToString(CultureInfo.InvariantCulture)),
_ => new Markup(CellValueIfMissing)
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="Spectre.Console" Version="0.49.1" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<!-- System.CommandLine depends on a vulnerable version -->
<PackageReference Include="System.Text.Json" Version="8.0.4" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit faef688

Please sign in to comment.