diff --git a/Directory.Packages.props b/Directory.Packages.props index 8c144c22..a3a98c65 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -34,6 +34,7 @@ + diff --git a/DiscordChatExporter.Cli.Tests/DiscordChatExporter.Cli.Tests.csproj b/DiscordChatExporter.Cli.Tests/DiscordChatExporter.Cli.Tests.csproj index 8cba1b16..a8becf93 100644 --- a/DiscordChatExporter.Cli.Tests/DiscordChatExporter.Cli.Tests.csproj +++ b/DiscordChatExporter.Cli.Tests/DiscordChatExporter.Cli.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs index 25e0cec9..58bf0788 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/DateRangeSpecs.cs @@ -5,11 +5,11 @@ using System.Threading.Tasks; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Exporting; using FluentAssertions; using JsonExtensions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs index 3b09786a..324278b6 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/FilterSpecs.cs @@ -5,11 +5,11 @@ using System.Threading.Tasks; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using DiscordChatExporter.Core.Exporting.Filtering; using FluentAssertions; using JsonExtensions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlContentSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlContentSpecs.cs index 601cfdd3..4b1e474d 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlContentSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlContentSpecs.cs @@ -8,6 +8,7 @@ using DiscordChatExporter.Cli.Tests.Infra; using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using FluentAssertions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs index a959d462..d204b8c0 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlEmbedSpecs.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using AngleSharp.Dom; using DiscordChatExporter.Cli.Tests.Infra; using DiscordChatExporter.Core.Discord; -using DiscordChatExporter.Core.Utils.Extensions; using FluentAssertions; +using PowerKit.Extensions; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlForwardSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlForwardSpecs.cs index 823c900e..24929c89 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlForwardSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlForwardSpecs.cs @@ -1,9 +1,9 @@ using System.Threading.Tasks; using AngleSharp.Dom; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils.Extensions; using DiscordChatExporter.Core.Discord; using FluentAssertions; +using PowerKit.Extensions; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; @@ -22,7 +22,7 @@ public class HtmlForwardSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .ContainAll("Forwarded", @"¯\_(ツ)_/¯", "12/29/2025 2:14 PM"); } diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlGroupingSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlGroupingSpecs.cs index 627a2468..c3bee420 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlGroupingSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlGroupingSpecs.cs @@ -8,6 +8,7 @@ using DiscordChatExporter.Cli.Tests.Infra; using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using FluentAssertions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/HtmlMarkdownSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/HtmlMarkdownSpecs.cs index c9623efb..c8496ada 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/HtmlMarkdownSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/HtmlMarkdownSpecs.cs @@ -1,9 +1,9 @@ using System.Threading.Tasks; using AngleSharp.Dom; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils.Extensions; using DiscordChatExporter.Core.Discord; using FluentAssertions; +using PowerKit.Extensions; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; @@ -22,11 +22,14 @@ public class HtmlMarkdownSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .Contain("Default timestamp: 2/12/2023 1:36 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -39,8 +42,11 @@ public class HtmlMarkdownSpecs ); // Assert - message.Text().ReplaceWhiteSpace().Should().Contain("Short time timestamp: 1:36 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message.Text().ReplaceWhiteSpace(' ').Should().Contain("Short time timestamp: 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -53,8 +59,11 @@ public class HtmlMarkdownSpecs ); // Assert - message.Text().ReplaceWhiteSpace().Should().Contain("Long time timestamp: 1:36:12 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message.Text().ReplaceWhiteSpace(' ').Should().Contain("Long time timestamp: 1:36:12 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -67,8 +76,11 @@ public class HtmlMarkdownSpecs ); // Assert - message.Text().ReplaceWhiteSpace().Should().Contain("Short date timestamp: 2/12/2023"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message.Text().ReplaceWhiteSpace(' ').Should().Contain("Short date timestamp: 2/12/2023"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -83,11 +95,14 @@ public class HtmlMarkdownSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .Contain("Long date timestamp: Sunday, February 12, 2023"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -102,11 +117,14 @@ public class HtmlMarkdownSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .Contain("Full timestamp: Sunday, February 12, 2023 1:36 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -121,11 +139,14 @@ public class HtmlMarkdownSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .Contain("Full long timestamp: Sunday, February 12, 2023 1:36:12 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] @@ -140,11 +161,14 @@ public class HtmlMarkdownSpecs // Assert message .Text() - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .Contain("Relative timestamp: 2/12/2023 1:36 PM"); - message.InnerHtml.ReplaceWhiteSpace().Should().Contain("Sunday, February 12, 2023 1:36 PM"); + message + .InnerHtml.ReplaceWhiteSpace(' ') + .Should() + .Contain("Sunday, February 12, 2023 1:36 PM"); } [Fact] diff --git a/DiscordChatExporter.Cli.Tests/Specs/JsonContentSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/JsonContentSpecs.cs index ec1e7f1f..dbe413c5 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/JsonContentSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/JsonContentSpecs.cs @@ -4,10 +4,10 @@ using System.Threading.Tasks; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using FluentAssertions; using JsonExtensions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; diff --git a/DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs index a763c9aa..89f27696 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/PartitioningSpecs.cs @@ -3,10 +3,10 @@ using System.Threading.Tasks; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using DiscordChatExporter.Core.Exporting.Partitioning; using FluentAssertions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; @@ -17,7 +17,7 @@ public class PartitioningSpecs public async Task I_can_export_a_channel_with_partitioning_based_on_message_count() { // Arrange - using var dir = TempDir.Create(); + using var dir = TempDirectory.Create(); var filePath = Path.Combine(dir.Path, "output.html"); // Act @@ -38,7 +38,7 @@ public class PartitioningSpecs public async Task I_can_export_a_channel_with_partitioning_based_on_file_size() { // Arrange - using var dir = TempDir.Create(); + using var dir = TempDirectory.Create(); var filePath = Path.Combine(dir.Path, "output.html"); // Act diff --git a/DiscordChatExporter.Cli.Tests/Specs/PlainTextForwardSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/PlainTextForwardSpecs.cs index 8d42a36e..2f8ef73c 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/PlainTextForwardSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/PlainTextForwardSpecs.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using DiscordChatExporter.Cli.Tests.Infra; -using DiscordChatExporter.Cli.Tests.Utils.Extensions; using FluentAssertions; +using PowerKit.Extensions; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; @@ -16,7 +16,7 @@ public class PlainTextForwardSpecs // Assert document - .ReplaceWhiteSpace() + .ReplaceWhiteSpace(' ') .Should() .ContainAll("{Forwarded Message}", @"¯\_(ツ)_/¯", "12/28/2025 10:52 PM"); } diff --git a/DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs b/DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs index b8a2d677..58865701 100644 --- a/DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs +++ b/DiscordChatExporter.Cli.Tests/Specs/SelfContainedSpecs.cs @@ -7,6 +7,7 @@ using DiscordChatExporter.Cli.Tests.Infra; using DiscordChatExporter.Cli.Tests.Utils; using DiscordChatExporter.Core.Exporting; using FluentAssertions; +using PowerKit; using Xunit; namespace DiscordChatExporter.Cli.Tests.Specs; @@ -17,7 +18,7 @@ public class SelfContainedSpecs public async Task I_can_export_a_channel_and_download_all_referenced_assets() { // Arrange - using var dir = TempDir.Create(); + using var dir = TempDirectory.Create(); var filePath = Path.Combine(dir.Path, "output.html"); // Act diff --git a/DiscordChatExporter.Cli.Tests/Utils/Extensions/StringExtensions.cs b/DiscordChatExporter.Cli.Tests/Utils/Extensions/StringExtensions.cs deleted file mode 100644 index 4db07483..00000000 --- a/DiscordChatExporter.Cli.Tests/Utils/Extensions/StringExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Text; - -namespace DiscordChatExporter.Cli.Tests.Utils.Extensions; - -internal static class StringExtensions -{ - extension(string str) - { - public string ReplaceWhiteSpace(string replacement = " ") - { - var buffer = new StringBuilder(str.Length); - - foreach (var ch in str) - buffer.Append(char.IsWhiteSpace(ch) ? replacement : ch); - - return buffer.ToString(); - } - } -} diff --git a/DiscordChatExporter.Cli.Tests/Utils/TempDir.cs b/DiscordChatExporter.Cli.Tests/Utils/TempDir.cs deleted file mode 100644 index e907755d..00000000 --- a/DiscordChatExporter.Cli.Tests/Utils/TempDir.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace DiscordChatExporter.Cli.Tests.Utils; - -internal partial class TempDir(string path) : IDisposable -{ - public string Path { get; } = path; - - public void Dispose() - { - try - { - Directory.Delete(Path, true); - } - catch (DirectoryNotFoundException) { } - } -} - -internal partial class TempDir -{ - public static TempDir Create() - { - var dirPath = System.IO.Path.Combine( - System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) - ?? Directory.GetCurrentDirectory(), - "Temp", - Guid.NewGuid().ToString() - ); - - Directory.CreateDirectory(dirPath); - - return new TempDir(dirPath); - } -} diff --git a/DiscordChatExporter.Cli.Tests/Utils/TempFile.cs b/DiscordChatExporter.Cli.Tests/Utils/TempFile.cs deleted file mode 100644 index 0a686a65..00000000 --- a/DiscordChatExporter.Cli.Tests/Utils/TempFile.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace DiscordChatExporter.Cli.Tests.Utils; - -internal partial class TempFile(string path) : IDisposable -{ - public string Path { get; } = path; - - public void Dispose() - { - try - { - File.Delete(Path); - } - catch (FileNotFoundException) { } - } -} - -internal partial class TempFile -{ - public static TempFile Create() - { - var dirPath = System.IO.Path.Combine( - System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) - ?? Directory.GetCurrentDirectory(), - "Temp" - ); - - Directory.CreateDirectory(dirPath); - - var filePath = System.IO.Path.Combine(dirPath, Guid.NewGuid() + ".tmp"); - - return new TempFile(filePath); - } -} diff --git a/DiscordChatExporter.Cli/Commands/ExportChannelsCommand.cs b/DiscordChatExporter.Cli/Commands/ExportChannelsCommand.cs index 3e963cad..832ae536 100644 --- a/DiscordChatExporter.Cli/Commands/ExportChannelsCommand.cs +++ b/DiscordChatExporter.Cli/Commands/ExportChannelsCommand.cs @@ -5,7 +5,7 @@ using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Cli.Commands; diff --git a/DiscordChatExporter.Cli/Commands/ExportDirectMessagesCommand.cs b/DiscordChatExporter.Cli/Commands/ExportDirectMessagesCommand.cs index 39f41f40..5fba63a7 100644 --- a/DiscordChatExporter.Cli/Commands/ExportDirectMessagesCommand.cs +++ b/DiscordChatExporter.Cli/Commands/ExportDirectMessagesCommand.cs @@ -3,7 +3,7 @@ using CliFx.Binding; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Cli.Commands; diff --git a/DiscordChatExporter.Cli/Commands/GetChannelsCommand.cs b/DiscordChatExporter.Cli/Commands/GetChannelsCommand.cs index b0116ed7..fb63a36a 100644 --- a/DiscordChatExporter.Cli/Commands/GetChannelsCommand.cs +++ b/DiscordChatExporter.Cli/Commands/GetChannelsCommand.cs @@ -7,7 +7,7 @@ using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Cli.Commands.Converters; using DiscordChatExporter.Cli.Commands.Shared; using DiscordChatExporter.Core.Discord; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Cli.Commands; diff --git a/DiscordChatExporter.Cli/Commands/GetDirectChannelsCommand.cs b/DiscordChatExporter.Cli/Commands/GetDirectChannelsCommand.cs index 06ea69b1..b1c8586e 100644 --- a/DiscordChatExporter.Cli/Commands/GetDirectChannelsCommand.cs +++ b/DiscordChatExporter.Cli/Commands/GetDirectChannelsCommand.cs @@ -5,7 +5,7 @@ using CliFx.Binding; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Cli.Commands; diff --git a/DiscordChatExporter.Cli/Commands/GetGuildsCommand.cs b/DiscordChatExporter.Cli/Commands/GetGuildsCommand.cs index 6d8b5410..626d05bb 100644 --- a/DiscordChatExporter.Cli/Commands/GetGuildsCommand.cs +++ b/DiscordChatExporter.Cli/Commands/GetGuildsCommand.cs @@ -5,7 +5,7 @@ using CliFx.Binding; using CliFx.Infrastructure; using DiscordChatExporter.Cli.Commands.Base; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Cli.Commands; diff --git a/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj b/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj index 2945ffa4..eed56c41 100644 --- a/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj +++ b/DiscordChatExporter.Cli/DiscordChatExporter.Cli.csproj @@ -11,6 +11,7 @@ + diff --git a/DiscordChatExporter.Core/Discord/Data/Application.cs b/DiscordChatExporter.Core/Discord/Data/Application.cs index 05309e64..2a18fb02 100644 --- a/DiscordChatExporter.Core/Discord/Data/Application.cs +++ b/DiscordChatExporter.Core/Discord/Data/Application.cs @@ -1,6 +1,6 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Attachment.cs b/DiscordChatExporter.Core/Discord/Data/Attachment.cs index 7d0a7ca6..f47776cb 100644 --- a/DiscordChatExporter.Core/Discord/Data/Attachment.cs +++ b/DiscordChatExporter.Core/Discord/Data/Attachment.cs @@ -2,8 +2,8 @@ using System.IO; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Channel.cs b/DiscordChatExporter.Core/Discord/Data/Channel.cs index 8511b47d..ef137170 100644 --- a/DiscordChatExporter.Core/Discord/Data/Channel.cs +++ b/DiscordChatExporter.Core/Discord/Data/Channel.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs index caa474e1..b9a29e83 100644 --- a/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs +++ b/DiscordChatExporter.Core/Discord/Data/Embeds/Embed.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data.Embeds; @@ -47,9 +47,7 @@ public partial record Embed var kind = json.GetPropertyOrNull("type") ?.GetStringOrNull() - ?.Pipe(s => - Enum.TryParse(s, true, out var result) ? result : (EmbedKind?)null - ) + .Pipe(s => Enum.ParseOrNull(s, true)) ?? EmbedKind.Rich; var url = json.GetPropertyOrNull("url")?.GetNonWhiteSpaceStringOrNull(); @@ -58,7 +56,7 @@ public partial record Embed var color = json.GetPropertyOrNull("color") ?.GetInt32OrNull() ?.Pipe(System.Drawing.Color.FromArgb) - .ResetAlpha(); + .WithFullAlpha(); var author = json.GetPropertyOrNull("author")?.Pipe(EmbedAuthor.Parse); var description = json.GetPropertyOrNull("description")?.GetStringOrNull(); diff --git a/DiscordChatExporter.Core/Discord/Data/Emoji.cs b/DiscordChatExporter.Core/Discord/Data/Emoji.cs index 31aafff7..b0bbb2e3 100644 --- a/DiscordChatExporter.Core/Discord/Data/Emoji.cs +++ b/DiscordChatExporter.Core/Discord/Data/Emoji.cs @@ -1,8 +1,8 @@ using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; using DiscordChatExporter.Core.Utils; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Guild.cs b/DiscordChatExporter.Core/Discord/Data/Guild.cs index fa2ade07..b9efdc7b 100644 --- a/DiscordChatExporter.Core/Discord/Data/Guild.cs +++ b/DiscordChatExporter.Core/Discord/Data/Guild.cs @@ -1,7 +1,7 @@ using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Interaction.cs b/DiscordChatExporter.Core/Discord/Data/Interaction.cs index 3a020d40..6b964df4 100644 --- a/DiscordChatExporter.Core/Discord/Data/Interaction.cs +++ b/DiscordChatExporter.Core/Discord/Data/Interaction.cs @@ -1,6 +1,6 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Invite.cs b/DiscordChatExporter.Core/Discord/Data/Invite.cs index 17d077f4..1c87a6d6 100644 --- a/DiscordChatExporter.Core/Discord/Data/Invite.cs +++ b/DiscordChatExporter.Core/Discord/Data/Invite.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.RegularExpressions; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Member.cs b/DiscordChatExporter.Core/Discord/Data/Member.cs index ec9487f4..4beb40b4 100644 --- a/DiscordChatExporter.Core/Discord/Data/Member.cs +++ b/DiscordChatExporter.Core/Discord/Data/Member.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Message.cs b/DiscordChatExporter.Core/Discord/Data/Message.cs index 9b1c4f92..c35c7690 100644 --- a/DiscordChatExporter.Core/Discord/Data/Message.cs +++ b/DiscordChatExporter.Core/Discord/Data/Message.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; using DiscordChatExporter.Core.Discord.Data.Embeds; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs index 48c68d5f..b6f2bf56 100644 --- a/DiscordChatExporter.Core/Discord/Data/MessageReference.cs +++ b/DiscordChatExporter.Core/Discord/Data/MessageReference.cs @@ -1,6 +1,6 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Reaction.cs b/DiscordChatExporter.Core/Discord/Data/Reaction.cs index 21e9c712..17117b47 100644 --- a/DiscordChatExporter.Core/Discord/Data/Reaction.cs +++ b/DiscordChatExporter.Core/Discord/Data/Reaction.cs @@ -1,5 +1,5 @@ using System.Text.Json; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/Role.cs b/DiscordChatExporter.Core/Discord/Data/Role.cs index 86616eff..999da66e 100644 --- a/DiscordChatExporter.Core/Discord/Data/Role.cs +++ b/DiscordChatExporter.Core/Discord/Data/Role.cs @@ -1,8 +1,8 @@ using System.Drawing; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; @@ -18,7 +18,7 @@ public record Role(Snowflake Id, string Name, int Position, Color? Color) : IHas var color = json.GetPropertyOrNull("color") ?.GetInt32OrNull() ?.Pipe(System.Drawing.Color.FromArgb) - .ResetAlpha() + .WithFullAlpha() .NullIf(c => c.ToRgb() <= 0); return new Role(id, name, position, color); diff --git a/DiscordChatExporter.Core/Discord/Data/Sticker.cs b/DiscordChatExporter.Core/Discord/Data/Sticker.cs index 76ea2486..79314455 100644 --- a/DiscordChatExporter.Core/Discord/Data/Sticker.cs +++ b/DiscordChatExporter.Core/Discord/Data/Sticker.cs @@ -1,8 +1,8 @@ using System; using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/Data/User.cs b/DiscordChatExporter.Core/Discord/Data/User.cs index ba1ec8fc..30e6992a 100644 --- a/DiscordChatExporter.Core/Discord/Data/User.cs +++ b/DiscordChatExporter.Core/Discord/Data/User.cs @@ -1,7 +1,7 @@ using System.Text.Json; using DiscordChatExporter.Core.Discord.Data.Common; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord.Data; diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index c3846136..b021b790 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -11,10 +11,10 @@ using System.Threading.Tasks; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Exceptions; using DiscordChatExporter.Core.Utils; -using DiscordChatExporter.Core.Utils.Extensions; using Gress; using JsonExtensions.Http; using JsonExtensions.Reading; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Discord; @@ -59,12 +59,12 @@ public class DiscordClient( { var remainingRequestCount = response .Headers.TryGetValue("X-RateLimit-Remaining") - ?.Pipe(s => int.Parse(s, CultureInfo.InvariantCulture)); + ?.Pipe(s => int.ParseOrNull(s, CultureInfo.InvariantCulture)); var resetAfterDelay = response .Headers.TryGetValue("X-RateLimit-Reset-After") - ?.Pipe(s => double.Parse(s, CultureInfo.InvariantCulture)) - .Pipe(TimeSpan.FromSeconds); + ?.Pipe(s => double.ParseOrNull(s, CultureInfo.InvariantCulture)) + ?.Pipe(TimeSpan.FromSeconds); // If this was the last request available before hitting the rate limit, // wait out the reset time so that future requests can succeed. @@ -161,7 +161,7 @@ public class DiscordClient( $""" Request to '{url}' failed: {response .StatusCode.ToString() - .ToSpaceSeparatedWords() + .SeparateWords(' ') .ToLowerInvariant()}. Response content: {await response.Content.ReadAsStringAsync( cancellationToken diff --git a/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj b/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj index 041356e5..efd2b93a 100644 --- a/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj +++ b/DiscordChatExporter.Core/DiscordChatExporter.Core.csproj @@ -6,6 +6,7 @@ + diff --git a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs index f6911ce3..fee4c387 100644 --- a/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/CsvMessageWriter.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs b/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs index 84cf4223..0260a20f 100644 --- a/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs +++ b/DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using System.Web; using AsyncKeyedLock; using DiscordChatExporter.Core.Utils; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/ExportContext.cs b/DiscordChatExporter.Core/Exporting/ExportContext.cs index 4b78e41a..b16fd6be 100644 --- a/DiscordChatExporter.Core/Exporting/ExportContext.cs +++ b/DiscordChatExporter.Core/Exporting/ExportContext.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Utils; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/ExportRequest.cs b/DiscordChatExporter.Core/Exporting/ExportRequest.cs index aae3a921..0bbaa76a 100644 --- a/DiscordChatExporter.Core/Exporting/ExportRequest.cs +++ b/DiscordChatExporter.Core/Exporting/ExportRequest.cs @@ -7,7 +7,7 @@ using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Exporting.Filtering; using DiscordChatExporter.Core.Exporting.Partitioning; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/HtmlMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/HtmlMarkdownVisitor.cs index 407913f6..ba4fa389 100644 --- a/DiscordChatExporter.Core/Exporting/HtmlMarkdownVisitor.cs +++ b/DiscordChatExporter.Core/Exporting/HtmlMarkdownVisitor.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Markdown.Parsing; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs index 6bb8cc11..43f820d3 100644 --- a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs @@ -9,8 +9,8 @@ using System.Threading.Tasks; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Discord.Data.Embeds; using DiscordChatExporter.Core.Markdown.Parsing; -using DiscordChatExporter.Core.Utils.Extensions; using JsonExtensions.Writing; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; @@ -55,7 +55,7 @@ internal class JsonMessageWriter(Stream stream, ExportContext context) Context.TryGetMember(user.Id)?.DisplayName ?? user.DisplayName ); - _writer.WriteString("color", Context.TryGetUserColor(user.Id)?.ToHex()); + _writer.WriteString("color", Context.TryGetUserColor(user.Id)?.ToHexString()); _writer.WriteBoolean("isBot", user.IsBot); if (includeRoles) @@ -109,7 +109,7 @@ internal class JsonMessageWriter(Stream stream, ExportContext context) _writer.WriteString("id", role.Id.ToString()); _writer.WriteString("name", role.Name); - _writer.WriteString("color", role.Color?.ToHex()); + _writer.WriteString("color", role.Color?.ToHexString()); _writer.WriteNumber("position", role.Position); _writer.WriteEndObject(); @@ -281,7 +281,7 @@ internal class JsonMessageWriter(Stream stream, ExportContext context) ); if (embed.Color is not null) - _writer.WriteString("color", embed.Color.Value.ToHex()); + _writer.WriteString("color", embed.Color.Value.ToHexString()); if (embed.Author is not null) { diff --git a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml index cefb8bfb..f0dba0de 100644 --- a/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml +++ b/DiscordChatExporter.Core/Exporting/MessageGroupTemplate.cshtml @@ -6,6 +6,7 @@ @using DiscordChatExporter.Core.Discord.Data.Embeds @using DiscordChatExporter.Core.Markdown.Parsing @using DiscordChatExporter.Core.Utils.Extensions +@using PowerKit.Extensions @inherits RazorBlade.HtmlTemplate diff --git a/DiscordChatExporter.Core/Exporting/PlainTextMarkdownVisitor.cs b/DiscordChatExporter.Core/Exporting/PlainTextMarkdownVisitor.cs index 95513ba4..d59bd102 100644 --- a/DiscordChatExporter.Core/Exporting/PlainTextMarkdownVisitor.cs +++ b/DiscordChatExporter.Core/Exporting/PlainTextMarkdownVisitor.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Threading.Tasks; using DiscordChatExporter.Core.Markdown; using DiscordChatExporter.Core.Markdown.Parsing; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Exporting/PlainTextMessageExtensions.cs b/DiscordChatExporter.Core/Exporting/PlainTextMessageExtensions.cs index 69a81d49..ab1aa23f 100644 --- a/DiscordChatExporter.Core/Exporting/PlainTextMessageExtensions.cs +++ b/DiscordChatExporter.Core/Exporting/PlainTextMessageExtensions.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Linq; using DiscordChatExporter.Core.Discord.Data; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Exporting; diff --git a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs index 4bb53ed6..e3362e66 100644 --- a/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs +++ b/DiscordChatExporter.Core/Markdown/Parsing/MarkdownParser.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text.RegularExpressions; using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Utils; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Markdown.Parsing; diff --git a/DiscordChatExporter.Core/Utils/Extensions/AsyncCollectionExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/AsyncCollectionExtensions.cs deleted file mode 100644 index 2af5e685..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/AsyncCollectionExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class AsyncCollectionExtensions -{ - extension(IAsyncEnumerable asyncEnumerable) - { - private async ValueTask> CollectAsync() - { - var list = new List(); - - await foreach (var i in asyncEnumerable) - list.Add(i); - - return list; - } - - public ValueTaskAwaiter> GetAwaiter() => - asyncEnumerable.CollectAsync().GetAwaiter(); - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/CollectionExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/CollectionExtensions.cs deleted file mode 100644 index abb1dd9a..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/CollectionExtensions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class CollectionExtensions -{ - extension(T obj) - { - public IEnumerable ToSingletonEnumerable() - { - yield return obj; - } - } - - extension(IEnumerable source) - where T : class - { - public IEnumerable WhereNotNull() - { - foreach (var o in source) - { - if (o is not null) - yield return o; - } - } - } - - extension(IEnumerable source) - where T : struct - { - public IEnumerable WhereNotNull() - { - foreach (var o in source) - { - if (o is not null) - yield return o.Value; - } - } - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/ColorExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/ColorExtensions.cs deleted file mode 100644 index a3ec6486..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/ColorExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Drawing; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class ColorExtensions -{ - extension(Color color) - { - public Color WithAlpha(int alpha) => Color.FromArgb(alpha, color); - - public Color ResetAlpha() => color.WithAlpha(255); - - public int ToRgb() => color.ToArgb() & 0xffffff; - - public string ToHex() => $"#{color.R:X2}{color.G:X2}{color.B:X2}"; - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/ExceptionExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/ExceptionExtensions.cs deleted file mode 100644 index e3d67f1f..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/ExceptionExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class ExceptionExtensions -{ - extension(Exception exception) - { - private void PopulateChildren(ICollection children) - { - if (exception is AggregateException aggregateException) - { - foreach (var innerException in aggregateException.InnerExceptions) - { - children.Add(innerException); - PopulateChildren(innerException, children); - } - } - else if (exception.InnerException is not null) - { - children.Add(exception.InnerException); - PopulateChildren(exception.InnerException, children); - } - } - - public IReadOnlyList GetSelfAndChildren() - { - var children = new List { exception }; - PopulateChildren(exception, children); - return children; - } - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/GenericExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/GenericExtensions.cs deleted file mode 100644 index 2c47995d..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/GenericExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class GenericExtensions -{ - extension(TIn input) - { - public TOut Pipe(Func transform) => transform(input); - } - - extension(T value) - where T : struct - { - public T? NullIf(Func predicate) => !predicate(value) ? value : null; - - public T? NullIfDefault() => - value.NullIf(v => EqualityComparer.Default.Equals(v, default)); - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/HttpExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/HttpExtensions.cs deleted file mode 100644 index 19841afc..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/HttpExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Net.Http.Headers; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class HttpExtensions -{ - extension(HttpHeaders headers) - { - public string? TryGetValue(string name) => - headers.TryGetValues(name, out var values) ? string.Concat(values) : null; - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/PathExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/PathExtensions.cs deleted file mode 100644 index 183fc13c..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/PathExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class PathExtensions -{ - // This is a union of invalid characters from Windows (NTFS/FAT32), Linux (ext4/XFS), and macOS (HFS+/APFS). - // We use this instead of Path.GetInvalidFileNameChars() because that only returns OS-specific characters, - // not filesystem-specific characters. It's possible to use, for example, an NTFS drive on Linux, - // which would make some additional characters invalid that are otherwise valid on Linux. - // https://github.com/Tyrrrz/DiscordChatExporter/issues/1452 - private static readonly char[] InvalidFileNameChars = - [ - '\0', // Null character - invalid on all filesystems - '/', // Path separator on Unix and Windows - '\\', // Path separator on Windows - ':', // Reserved on Windows (drive letters, NTFS streams) - '*', // Wildcard on Windows - '?', // Wildcard on Windows - '"', // Reserved on Windows - '<', // Redirection on Windows - '>', // Redirection on Windows - '|', // Pipe on Windows - ]; - - extension(Path) - { - public static string EscapeFileName(string path) - { - var buffer = new StringBuilder(path.Length); - - foreach (var c in path) - buffer.Append(!InvalidFileNameChars.Contains(c) ? c : '_'); - - // File names cannot end with a dot on Windows - // https://github.com/Tyrrrz/DiscordChatExporter/issues/977 - if (OperatingSystem.IsWindows()) - { - while (buffer.Length > 0 && buffer[^1] == '.') - buffer.Remove(buffer.Length - 1, 1); - } - - return buffer.ToString(); - } - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs deleted file mode 100644 index cc84267a..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Text; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class StringExtensions -{ - extension(string str) - { - public string? NullIfWhiteSpace() => !string.IsNullOrWhiteSpace(str) ? str : null; - - public string Truncate(int charCount) => str.Length > charCount ? str[..charCount] : str; - - public string ToSpaceSeparatedWords() - { - var builder = new StringBuilder(str.Length * 2); - - foreach (var c in str) - { - if (char.IsUpper(c) && builder.Length > 0) - builder.Append(' '); - - builder.Append(c); - } - - return builder.ToString(); - } - } - - extension(StringBuilder builder) - { - public StringBuilder AppendIfNotEmpty(char value) => - builder.Length > 0 ? builder.Append(value) : builder; - } -} diff --git a/DiscordChatExporter.Core/Utils/Extensions/TimeSpanExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/TimeSpanExtensions.cs deleted file mode 100644 index 9d838b09..00000000 --- a/DiscordChatExporter.Core/Utils/Extensions/TimeSpanExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace DiscordChatExporter.Core.Utils.Extensions; - -public static class TimeSpanExtensions -{ - extension(TimeSpan value) - { - public TimeSpan Clamp(TimeSpan min, TimeSpan max) - { - if (value < min) - return min; - - if (value > max) - return max; - - return value; - } - } -} diff --git a/DiscordChatExporter.Core/Utils/Http.cs b/DiscordChatExporter.Core/Utils/Http.cs index 7ed0b47c..49c6d9ab 100644 --- a/DiscordChatExporter.Core/Utils/Http.cs +++ b/DiscordChatExporter.Core/Utils/Http.cs @@ -5,9 +5,9 @@ using System.Net.Http; using System.Net.Sockets; using System.Security.Authentication; using System.Threading.Tasks; -using DiscordChatExporter.Core.Utils.Extensions; using Polly; using Polly.Retry; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Utils; @@ -24,7 +24,7 @@ public static class Http private static bool IsRetryableException(Exception exception) => exception - .GetSelfAndChildren() + .GetSelfAndDescendants() .Any(ex => ex is TimeoutException or SocketException or AuthenticationException || ex is HttpRequestException hrex diff --git a/DiscordChatExporter.Core/Utils/UrlBuilder.cs b/DiscordChatExporter.Core/Utils/UrlBuilder.cs index 2622bf25..f1c3b064 100644 --- a/DiscordChatExporter.Core/Utils/UrlBuilder.cs +++ b/DiscordChatExporter.Core/Utils/UrlBuilder.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using DiscordChatExporter.Core.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Core.Utils; diff --git a/DiscordChatExporter.Gui/App.axaml.cs b/DiscordChatExporter.Gui/App.axaml.cs index 975b34ae..af71f607 100644 --- a/DiscordChatExporter.Gui/App.axaml.cs +++ b/DiscordChatExporter.Gui/App.axaml.cs @@ -7,13 +7,13 @@ using Avalonia.Platform; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; -using DiscordChatExporter.Gui.Utils; -using DiscordChatExporter.Gui.Utils.Extensions; using DiscordChatExporter.Gui.ViewModels; using DiscordChatExporter.Gui.ViewModels.Components; using DiscordChatExporter.Gui.ViewModels.Dialogs; using Material.Styles.Themes; using Microsoft.Extensions.DependencyInjection; +using PowerKit; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui; @@ -22,7 +22,7 @@ public class App : Application, IDisposable private readonly ServiceProvider _services; private readonly SettingsService _settingsService; - private readonly DisposableCollector _eventRoot = new(); + private readonly IDisposable _eventSubscription; private bool _isDisposed; @@ -54,7 +54,7 @@ public class App : Application, IDisposable _settingsService = _services.GetRequiredService(); // Re-initialize the theme when the user changes it - _eventRoot.Add( + _eventSubscription = Disposable.Merge( _settingsService.WatchProperty( o => o.Theme, v => @@ -131,7 +131,7 @@ public class App : Application, IDisposable _isDisposed = true; - _eventRoot.Dispose(); + _eventSubscription.Dispose(); _services.Dispose(); } } diff --git a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj index b9b2baff..94ed5edf 100644 --- a/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj +++ b/DiscordChatExporter.Gui/DiscordChatExporter.Gui.csproj @@ -41,6 +41,7 @@ + diff --git a/DiscordChatExporter.Gui/Localization/LocalizationManager.cs b/DiscordChatExporter.Gui/Localization/LocalizationManager.cs index de917565..9b8fdfba 100644 --- a/DiscordChatExporter.Gui/Localization/LocalizationManager.cs +++ b/DiscordChatExporter.Gui/Localization/LocalizationManager.cs @@ -3,20 +3,19 @@ using System.Globalization; using System.Runtime.CompilerServices; using CommunityToolkit.Mvvm.ComponentModel; using DiscordChatExporter.Gui.Services; -using DiscordChatExporter.Gui.Utils; -using DiscordChatExporter.Gui.Utils.Extensions; +using PowerKit; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.Localization; public partial class LocalizationManager : ObservableObject, IDisposable { - private readonly DisposableCollector _eventRoot = new(); + private readonly IDisposable _eventSubscription; public LocalizationManager(SettingsService settingsService) { - _eventRoot.Add(settingsService.WatchProperty(o => o.Language, v => Language = v, true)); - - _eventRoot.Add( + _eventSubscription = Disposable.Merge( + settingsService.WatchProperty(o => o.Language, v => Language = v, true), this.WatchProperty( o => o.Language, _ => @@ -66,7 +65,7 @@ public partial class LocalizationManager : ObservableObject, IDisposable return $"Missing localization for '{key}'"; } - public void Dispose() => _eventRoot.Dispose(); + public void Dispose() => _eventSubscription.Dispose(); } public partial class LocalizationManager diff --git a/DiscordChatExporter.Gui/Utils/Disposable.cs b/DiscordChatExporter.Gui/Utils/Disposable.cs deleted file mode 100644 index e7bdfb63..00000000 --- a/DiscordChatExporter.Gui/Utils/Disposable.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace DiscordChatExporter.Gui.Utils; - -internal class Disposable(Action dispose) : IDisposable -{ - public static IDisposable Create(Action dispose) => new Disposable(dispose); - - public void Dispose() => dispose(); -} diff --git a/DiscordChatExporter.Gui/Utils/DisposableCollector.cs b/DiscordChatExporter.Gui/Utils/DisposableCollector.cs deleted file mode 100644 index e96761b9..00000000 --- a/DiscordChatExporter.Gui/Utils/DisposableCollector.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using DiscordChatExporter.Gui.Utils.Extensions; - -namespace DiscordChatExporter.Gui.Utils; - -internal class DisposableCollector : IDisposable -{ - private readonly object _lock = new(); - private readonly List _items = []; - - public void Add(IDisposable item) - { - lock (_lock) - { - _items.Add(item); - } - } - - public void Dispose() - { - lock (_lock) - { - _items.DisposeAll(); - _items.Clear(); - } - } -} diff --git a/DiscordChatExporter.Gui/Utils/Extensions/CommandExtensions.cs b/DiscordChatExporter.Gui/Utils/Extensions/CommandExtensions.cs deleted file mode 100644 index fc0008cb..00000000 --- a/DiscordChatExporter.Gui/Utils/Extensions/CommandExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Windows.Input; - -namespace DiscordChatExporter.Gui.Utils.Extensions; - -internal static class CommandExtensions -{ - extension(ICommand command) - { - public void ExecuteIfCan(object? parameter = null) - { - if (command.CanExecute(parameter)) - command.Execute(parameter); - } - } -} diff --git a/DiscordChatExporter.Gui/Utils/Extensions/DisposableExtensions.cs b/DiscordChatExporter.Gui/Utils/Extensions/DisposableExtensions.cs deleted file mode 100644 index 553526bd..00000000 --- a/DiscordChatExporter.Gui/Utils/Extensions/DisposableExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace DiscordChatExporter.Gui.Utils.Extensions; - -internal static class DisposableExtensions -{ - extension(IEnumerable disposables) - { - public void DisposeAll() - { - var exceptions = default(List); - - foreach (var disposable in disposables) - { - try - { - disposable.Dispose(); - } - catch (Exception ex) - { - (exceptions ??= []).Add(ex); - } - } - - if (exceptions?.Any() == true) - throw new AggregateException(exceptions); - } - } -} diff --git a/DiscordChatExporter.Gui/Utils/Extensions/NotifyPropertyChangedExtensions.cs b/DiscordChatExporter.Gui/Utils/Extensions/NotifyPropertyChangedExtensions.cs deleted file mode 100644 index eef1583f..00000000 --- a/DiscordChatExporter.Gui/Utils/Extensions/NotifyPropertyChangedExtensions.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; - -namespace DiscordChatExporter.Gui.Utils.Extensions; - -internal static class NotifyPropertyChangedExtensions -{ - extension(TOwner owner) - where TOwner : INotifyPropertyChanged - { - public IDisposable WatchProperty( - Expression> propertyExpression, - Action callback, - bool watchInitialValue = false - ) - { - var memberExpression = propertyExpression.Body as MemberExpression; - if (memberExpression?.Member is not PropertyInfo property) - throw new ArgumentException("Provided expression must reference a property."); - - var getValue = propertyExpression.Compile(); - - void OnPropertyChanged(object? sender, PropertyChangedEventArgs args) - { - if ( - string.IsNullOrWhiteSpace(args.PropertyName) - || string.Equals(args.PropertyName, property.Name, StringComparison.Ordinal) - ) - { - callback(getValue(owner)); - } - } - - owner.PropertyChanged += OnPropertyChanged; - - if (watchInitialValue) - callback(getValue(owner)); - - return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged); - } - - public IDisposable WatchAllProperties(Action callback, bool watchInitialValues = false) - { - void OnPropertyChanged(object? sender, PropertyChangedEventArgs args) => callback(); - owner.PropertyChanged += OnPropertyChanged; - - if (watchInitialValues) - callback(); - - return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged); - } - } -} diff --git a/DiscordChatExporter.Gui/Utils/Extensions/ProcessExtensions.cs b/DiscordChatExporter.Gui/Utils/Extensions/ProcessExtensions.cs deleted file mode 100644 index 07317d21..00000000 --- a/DiscordChatExporter.Gui/Utils/Extensions/ProcessExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Diagnostics; - -namespace DiscordChatExporter.Gui.Utils.Extensions; - -internal static class ProcessExtensions -{ - extension(Process) - { - public static void StartShellExecute(string path) - { - using var process = new Process(); - process.StartInfo = new ProcessStartInfo(path) { UseShellExecute = true }; - - process.Start(); - } - } -} diff --git a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs index dd7a8454..1d1866cd 100644 --- a/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Components/DashboardViewModel.cs @@ -10,15 +10,14 @@ using DiscordChatExporter.Core.Discord; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Exceptions; using DiscordChatExporter.Core.Exporting; -using DiscordChatExporter.Core.Utils.Extensions; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Models; using DiscordChatExporter.Gui.Services; -using DiscordChatExporter.Gui.Utils; -using DiscordChatExporter.Gui.Utils.Extensions; using Gress; using Gress.Completable; +using PowerKit; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.ViewModels.Components; @@ -29,7 +28,7 @@ public partial class DashboardViewModel : ViewModelBase private readonly DialogManager _dialogManager; private readonly SettingsService _settingsService; - private readonly DisposableCollector _eventRoot = new(); + private readonly IDisposable _eventSubscription; private readonly AutoResetProgressMuxer _progressMuxer; private DiscordClient? _discord; @@ -50,14 +49,11 @@ public partial class DashboardViewModel : ViewModelBase _progressMuxer = Progress.CreateMuxer().WithAutoReset(); - _eventRoot.Add( + _eventSubscription = Disposable.Merge( Progress.WatchProperty( o => o.Current, _ => OnPropertyChanged(nameof(IsProgressIndeterminate)) - ) - ); - - _eventRoot.Add( + ), SelectedChannels.WatchProperty( o => o.Count, _ => ExportCommand.NotifyCanExecuteChanged() @@ -332,7 +328,7 @@ public partial class DashboardViewModel : ViewModelBase { if (disposing) { - _eventRoot.Dispose(); + _eventSubscription.Dispose(); } base.Dispose(disposing); diff --git a/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs index 5a43e646..e1c8705a 100644 --- a/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Dialogs/ExportSetupViewModel.cs @@ -10,10 +10,10 @@ using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Core.Exporting; using DiscordChatExporter.Core.Exporting.Filtering; using DiscordChatExporter.Core.Exporting.Partitioning; -using DiscordChatExporter.Core.Utils.Extensions; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.ViewModels.Dialogs; diff --git a/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs b/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs index 143246ca..c1c19543 100644 --- a/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/Dialogs/SettingsViewModel.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; using DiscordChatExporter.Core.Discord; -using DiscordChatExporter.Core.Utils.Extensions; using DiscordChatExporter.Gui.Framework; using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Models; using DiscordChatExporter.Gui.Services; -using DiscordChatExporter.Gui.Utils; -using DiscordChatExporter.Gui.Utils.Extensions; +using PowerKit; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.ViewModels.Dialogs; @@ -15,7 +14,7 @@ public class SettingsViewModel : DialogViewModelBase { private readonly SettingsService _settingsService; - private readonly DisposableCollector _eventRoot = new(); + private readonly IDisposable _eventSubscription; public SettingsViewModel( SettingsService settingsService, @@ -25,7 +24,9 @@ public class SettingsViewModel : DialogViewModelBase _settingsService = settingsService; LocalizationManager = localizationManager; - _eventRoot.Add(_settingsService.WatchAllProperties(OnAllPropertiesChanged)); + _eventSubscription = Disposable.Merge( + _settingsService.WatchAllProperties(OnAllPropertiesChanged) + ); } public LocalizationManager LocalizationManager { get; } @@ -140,7 +141,7 @@ public class SettingsViewModel : DialogViewModelBase { if (disposing) { - _eventRoot.Dispose(); + _eventSubscription.Dispose(); } base.Dispose(disposing); diff --git a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs index ca428c63..b4715d8e 100644 --- a/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs +++ b/DiscordChatExporter.Gui/ViewModels/MainViewModel.cs @@ -7,6 +7,7 @@ using DiscordChatExporter.Gui.Localization; using DiscordChatExporter.Gui.Services; using DiscordChatExporter.Gui.Utils.Extensions; using DiscordChatExporter.Gui.ViewModels.Components; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.ViewModels; diff --git a/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml.cs b/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml.cs index 6155a55d..4bd49841 100644 --- a/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml.cs +++ b/DiscordChatExporter.Gui/Views/Components/DashboardView.axaml.cs @@ -4,8 +4,8 @@ using Avalonia.Input; using Avalonia.Interactivity; using DiscordChatExporter.Core.Discord.Data; using DiscordChatExporter.Gui.Framework; -using DiscordChatExporter.Gui.Utils.Extensions; using DiscordChatExporter.Gui.ViewModels.Components; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.Views.Components; diff --git a/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs b/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs index 72ed47a8..d8d94dc6 100644 --- a/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs +++ b/DiscordChatExporter.Gui/Views/Controls/HyperLink.axaml.cs @@ -3,7 +3,7 @@ using System.Windows.Input; using Avalonia; using Avalonia.Controls; using Avalonia.Input; -using DiscordChatExporter.Gui.Utils.Extensions; +using PowerKit.Extensions; namespace DiscordChatExporter.Gui.Views.Controls;