From 9550f7553c8b32bb2ae6b9a1f54873dd703462d2 Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:42:35 +0000 Subject: [PATCH 001/202] Renaming project files for v9.0.0 --- Jeebs (v8).sln => Jeebs (v9).sln | 2 +- jeebs-v8.code-workspace => jeebs-v9.code-workspace | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Jeebs (v8).sln => Jeebs (v9).sln (99%) rename jeebs-v8.code-workspace => jeebs-v9.code-workspace (100%) diff --git a/Jeebs (v8).sln b/Jeebs (v9).sln similarity index 99% rename from Jeebs (v8).sln rename to Jeebs (v9).sln index 51db86668..fe217aedd 100644 --- a/Jeebs (v8).sln +++ b/Jeebs (v9).sln @@ -72,8 +72,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .gitignore = .gitignore Directory.Packages.props = Directory.Packages.props - jeebs-v8.code-workspace = jeebs-v8.code-workspace LICENSE = LICENSE + jeebs-v9.code-workspace = jeebs-v9.code-workspace Pack.csproj = Pack.csproj .github\workflows\publish.yml = .github\workflows\publish.yml README.md = README.md diff --git a/jeebs-v8.code-workspace b/jeebs-v9.code-workspace similarity index 100% rename from jeebs-v8.code-workspace rename to jeebs-v9.code-workspace From 9fb321e461d037675cfd69c3f192c01dd9dde8aa Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:42:45 +0000 Subject: [PATCH 002/202] Adding v9 to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 791215128..369497f2c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ I am definitely a backend developer at heart, although like everyone I have to w The code in these libraries has been under active development and use for over a decade, powering all my own websites, and some for other people as well. +### Jeebs v9 + +Jeebs v9 targets .NET 8 and brings in various optimisations and a re-write of the authentication projects. + ### Jeebs v8 Jeebs v8 targets .NET 7, applies StyleCop conventions and best practices, and removes two utility projects (`Maybe` and `Random`) to separate repos / packages (see [here](https://github.com/bfren/maybe) and [here](https://github.com/bfren/rnd)). From 8a7fa2819c0e13bcca80263c39a24196e656b17a Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:45:30 +0000 Subject: [PATCH 003/202] Renaming DispatchAsync to SendAsync - #434 --- src/Jeebs.Cqrs/Dispatcher.cs | 9 +++- src/Jeebs.Cqrs/IDispatcher.cs | 11 ++++- src/Jeebs.Cqrs/Internals/ICommandHandler.cs | 2 +- src/Jeebs.Cqrs/Internals/IQueryHandler.cs | 2 +- ...patchAsync_Tests.cs => SendAsync_Tests.cs} | 45 ++++++++++--------- 5 files changed, 41 insertions(+), 28 deletions(-) rename tests/Tests.Jeebs.Cqrs/_/Dispatcher/{DispatchAsync_Tests.cs => SendAsync_Tests.cs} (65%) diff --git a/src/Jeebs.Cqrs/Dispatcher.cs b/src/Jeebs.Cqrs/Dispatcher.cs index e14deac70..351a33671 100644 --- a/src/Jeebs.Cqrs/Dispatcher.cs +++ b/src/Jeebs.Cqrs/Dispatcher.cs @@ -25,7 +25,7 @@ public Dispatcher(IServiceProvider provider, ILog log) => (Provider, Log) = (provider, log); /// - public Task> DispatchAsync(Command command) + public Task> SendAsync(Command command) { var service = GetHandlerService(typeof(CommandHandler<>), command.GetType()); return service switch @@ -39,7 +39,12 @@ public Task> DispatchAsync(Command command) } /// - public Task> DispatchAsync(Query query) + public Task> SendAsync() + where TCommand : Command, new() => + SendAsync(new TCommand()); + + /// + public Task> SendAsync(Query query) { var service = GetHandlerService(typeof(QueryHandler<,>), query.GetType(), typeof(TResult)); return service switch diff --git a/src/Jeebs.Cqrs/IDispatcher.cs b/src/Jeebs.Cqrs/IDispatcher.cs index 8400111a3..12a1cfc62 100644 --- a/src/Jeebs.Cqrs/IDispatcher.cs +++ b/src/Jeebs.Cqrs/IDispatcher.cs @@ -14,12 +14,19 @@ public interface IDispatcher /// Call for /// /// Command object - Task> DispatchAsync(Command command); + Task> SendAsync(Command command); + + /// + /// Call for + /// + /// + Task> SendAsync() + where TCommand : Command, new(); /// /// Call for /// /// Query result value type /// Query object - Task> DispatchAsync(Query query); + Task> SendAsync(Query query); } diff --git a/src/Jeebs.Cqrs/Internals/ICommandHandler.cs b/src/Jeebs.Cqrs/Internals/ICommandHandler.cs index c8c2d6403..fd5cf8d63 100644 --- a/src/Jeebs.Cqrs/Internals/ICommandHandler.cs +++ b/src/Jeebs.Cqrs/Internals/ICommandHandler.cs @@ -7,7 +7,7 @@ namespace Jeebs.Cqrs.Internals; /// /// Command handler interface which allows generic dispatching - see -/// +/// /// internal interface ICommandHandler { diff --git a/src/Jeebs.Cqrs/Internals/IQueryHandler.cs b/src/Jeebs.Cqrs/Internals/IQueryHandler.cs index 037dbd353..18fdcec6d 100644 --- a/src/Jeebs.Cqrs/Internals/IQueryHandler.cs +++ b/src/Jeebs.Cqrs/Internals/IQueryHandler.cs @@ -7,7 +7,7 @@ namespace Jeebs.Cqrs.Internals; /// /// Query handler interface which allows generic dispatching - see -/// +/// /// /// Query result value type internal interface IQueryHandler diff --git a/tests/Tests.Jeebs.Cqrs/_/Dispatcher/DispatchAsync_Tests.cs b/tests/Tests.Jeebs.Cqrs/_/Dispatcher/SendAsync_Tests.cs similarity index 65% rename from tests/Tests.Jeebs.Cqrs/_/Dispatcher/DispatchAsync_Tests.cs rename to tests/Tests.Jeebs.Cqrs/_/Dispatcher/SendAsync_Tests.cs index d251f5342..30125c492 100644 --- a/tests/Tests.Jeebs.Cqrs/_/Dispatcher/DispatchAsync_Tests.cs +++ b/tests/Tests.Jeebs.Cqrs/_/Dispatcher/SendAsync_Tests.cs @@ -6,7 +6,7 @@ namespace Jeebs.Cqrs.Dispatcher_Tests; -public class DispatchAsync_Tests +public class SendAsync_Tests { public class With_Command { @@ -17,39 +17,40 @@ public async Task Unregistered_Handler_Returns_None_With_UnableToGetCommandHandl var provider = Substitute.For(); var log = Substitute.For>(); var dispatcher = new Dispatcher(provider, log); - var command = new Command(); + var command = new TestCommand(); // Act - var r0 = await dispatcher.DispatchAsync(command); - var r1 = await dispatcher.DispatchAsync(command); + var r0 = await dispatcher.SendAsync(command); + var r1 = await dispatcher.SendAsync(command); // Assert var n0 = r0.AssertNone(); var m0 = Assert.IsAssignableFrom(n0); - Assert.Equal(typeof(Command), m0.Value); + Assert.Equal(typeof(TestCommand), m0.Value); var n1 = r1.AssertNone(); var m1 = Assert.IsAssignableFrom(n1); - Assert.Equal(typeof(Command), m1.Value); + Assert.Equal(typeof(TestCommand), m1.Value); } [Fact] public async Task Runs_CommandHandler_HandleAsync() { // Arrange - var handler = Substitute.For>(); + var handler = Substitute.For>(); var provider = Substitute.For(); provider.GetService(default!) .ReturnsForAnyArgs(handler); var log = Substitute.For>(); var dispatcher = new Dispatcher(provider, log); - var command = new Command(); + var command = new TestCommand(); // Act - await dispatcher.DispatchAsync(command); - await dispatcher.DispatchAsync(command); + await dispatcher.SendAsync(command); + await dispatcher.SendAsync(command); + await dispatcher.SendAsync(); // Assert - await handler.Received(2).HandleAsync(command); + await handler.Received(3).HandleAsync(command); } } @@ -62,43 +63,43 @@ public async Task Unregistered_Handler_Returns_None_With_UnableToGetQueryHandler var provider = Substitute.For(); var log = Substitute.For>(); var dispatcher = new Dispatcher(provider, log); - var query = new Query(); + var query = new TestQuery(); // Act - var r0 = await dispatcher.DispatchAsync(query); - var r1 = await dispatcher.DispatchAsync(query); + var r0 = await dispatcher.SendAsync(query); + var r1 = await dispatcher.SendAsync(query); // Assert var n0 = r0.AssertNone(); var m0 = Assert.IsAssignableFrom(n0); - Assert.Equal(typeof(Query), m0.Value); + Assert.Equal(typeof(TestQuery), m0.Value); var n1 = r1.AssertNone(); var m1 = Assert.IsAssignableFrom(n1); - Assert.Equal(typeof(Query), m1.Value); + Assert.Equal(typeof(TestQuery), m1.Value); } [Fact] public async Task Runs_QueryHandler_HandleAsync() { // Arrange - var handler = Substitute.For>(); + var handler = Substitute.For>(); var provider = Substitute.For(); provider.GetService(default!) .ReturnsForAnyArgs(handler); var log = Substitute.For>(); var dispatcher = new Dispatcher(provider, log); - var query = new Query(); + var query = new TestQuery(); // Act - await dispatcher.DispatchAsync(query); - await dispatcher.DispatchAsync(query); + await dispatcher.SendAsync(query); + await dispatcher.SendAsync(query); // Assert await handler.Received(2).HandleAsync(query); } } - public sealed record class Command : Cqrs.Command; + public sealed record class TestCommand : Command; - public sealed record class Query : Query; + public sealed record class TestQuery : Query; } From 73a9dc26e5fbdda50bda58ee38dab952984a3a80 Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:45:46 +0000 Subject: [PATCH 004/202] Fixing comment - #434 --- src/Jeebs.Cqrs/Messages/IncorrectCommandTypeMsg.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Jeebs.Cqrs/Messages/IncorrectCommandTypeMsg.cs b/src/Jeebs.Cqrs/Messages/IncorrectCommandTypeMsg.cs index 893f7b739..282633b8e 100644 --- a/src/Jeebs.Cqrs/Messages/IncorrectCommandTypeMsg.cs +++ b/src/Jeebs.Cqrs/Messages/IncorrectCommandTypeMsg.cs @@ -6,7 +6,7 @@ namespace Jeebs.Cqrs.Messages; -/// The query is an incorrect type for the handler -/// Expected query type -/// Actual query type +/// The command is an incorrect type for the handler +/// Expected command type +/// Actual command type public sealed record class IncorrectCommandTypeMsg(Type ExpectedType, Type ActualType) : Msg; From c2f8fd0f1e5101d027f9d60a350041c8076a006b Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:50:35 +0000 Subject: [PATCH 005/202] Adding Lock() extension method - #436 --- .../ObjectExtensions.Lock.cs | 39 +++++++++++++++ .../_/ObjectExtensions/Lock_Tests.cs | 49 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/Jeebs.Cryptography/ObjectExtensions.Lock.cs create mode 100644 tests/Tests.Jeebs.Cryptography/_/ObjectExtensions/Lock_Tests.cs diff --git a/src/Jeebs.Cryptography/ObjectExtensions.Lock.cs b/src/Jeebs.Cryptography/ObjectExtensions.Lock.cs new file mode 100644 index 000000000..45bb187e7 --- /dev/null +++ b/src/Jeebs.Cryptography/ObjectExtensions.Lock.cs @@ -0,0 +1,39 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Cryptography; + +public static partial class ObjectExtensions +{ + /// + /// Encrypt an object using the specified key and return it serialised as JSON + /// + /// Type of object being encrypted + /// Value to encrypt + /// Encryption Key (must be 32 bytes) + public static Maybe> Lock(this T @this, byte[] key) => + @this switch + { + T x => + new Lockable(x).Lock(key), + + _ => + new Locked() + }; + + /// + /// Encrypt an object using the specified key and return it serialised as JSON + /// + /// Type of object being encrypted + /// Value to encrypt + /// Encryption key + public static Locked Lock(this T @this, string key) => + @this switch + { + T x => + new Lockable(x).Lock(key), + + _ => + new Locked() + }; +} diff --git a/tests/Tests.Jeebs.Cryptography/_/ObjectExtensions/Lock_Tests.cs b/tests/Tests.Jeebs.Cryptography/_/ObjectExtensions/Lock_Tests.cs new file mode 100644 index 000000000..917ba29ac --- /dev/null +++ b/tests/Tests.Jeebs.Cryptography/_/ObjectExtensions/Lock_Tests.cs @@ -0,0 +1,49 @@ +// Jeebs Unit Tests +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using static Jeebs.Cryptography.Lockable.M; + +namespace Jeebs.Cryptography.ObjectExtensions_Tests; + +public sealed class Lock_Tests +{ + [Fact] + public void Incorrect_Key_Length_Returns_None_With_InvalidKeyLengthMsg() + { + // Arrange + var key = Rnd.ByteF.Get(20); + + // Act + var result = Rnd.Guid.Lock(key); + + // Assert + result.AssertNone().AssertType(); + } + + [Fact] + public void Byte_Key_Returns_Locked() + { + // Arrange + var key = Rnd.ByteF.Get(32); + + // Act + var result = Rnd.Guid.Lock(key); + + // Assert + var some = result.AssertSome(); + Assert.NotNull(some.EncryptedContents); + } + + [Fact] + public void String_Key_Returns_Locked() + { + // Arrange + var key = Rnd.Str; + + // Act + var result = Rnd.Guid.Lock(key); + + // Assert + Assert.NotNull(result.EncryptedContents); + } +} From 5caa869770f9fd2b7132a22c2a7f43de09f080cd Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 23 Mar 2023 11:54:16 +0000 Subject: [PATCH 006/202] Updating references from v8 to v9 --- src/Directory.Build.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 5db7caf1b..dcd105094 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -29,7 +29,7 @@ - $([MSBuild]::GetPathOfFileAbove('Jeebs (v8).sln')) + $([MSBuild]::GetPathOfFileAbove('Jeebs (v9).sln')) $([System.IO.Path]::GetDirectoryName('$(SolutionFilePath)')) @@ -85,8 +85,8 @@ --> - true - 8.2.0 + false + 8.3.0 From 1ff92f09d4c350c72be7e6d8180674b970189462 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 29 Apr 2023 13:19:25 +0100 Subject: [PATCH 007/202] Updating packages --- Directory.Packages.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 7c7f7fccf..46e0c58c2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -28,11 +28,11 @@ - + - - + + @@ -53,7 +53,7 @@ - + From a8f0717cea4a2a5873e865e27188f6803830ac18 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 29 Apr 2023 13:20:24 +0100 Subject: [PATCH 008/202] Removing GitHub actions from solution files --- Jeebs (v9).sln | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Jeebs (v9).sln b/Jeebs (v9).sln index fe217aedd..f5873c8df 100644 --- a/Jeebs (v9).sln +++ b/Jeebs (v9).sln @@ -72,15 +72,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .gitignore = .gitignore Directory.Packages.props = Directory.Packages.props - LICENSE = LICENSE jeebs-v9.code-workspace = jeebs-v9.code-workspace + LICENSE = LICENSE Pack.csproj = Pack.csproj - .github\workflows\publish.yml = .github\workflows\publish.yml README.md = README.md Test.csproj = Test.csproj - .github\workflows\test.yml = .github\workflows\test.yml Version = Version - .github\workflows\workflow-cleanup.yml = .github\workflows\workflow-cleanup.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Services", ".Services", "{6C31552E-8082-4D9A-BA93-A6BA41A47000}" From 8c260c579753934f1619f0b58cf58ae3984dd460 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 29 Apr 2023 13:21:08 +0100 Subject: [PATCH 009/202] Renaming Dispatcher.DispatchAsync - #434 --- apps/AppApi/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/AppApi/Program.cs b/apps/AppApi/Program.cs index ada493abb..d199f4202 100644 --- a/apps/AppApi/Program.cs +++ b/apps/AppApi/Program.cs @@ -21,7 +21,7 @@ [FromRoute] string name ) { var text = await query - .DispatchAsync( + .SendAsync( new SayHelloQuery(name) ) .UnwrapAsync( From fb1c8adc9a264fd6cd8962885d950735b762b669 Mon Sep 17 00:00:00 2001 From: bfren Date: Mon, 8 May 2023 12:26:15 +0100 Subject: [PATCH 010/202] Improving ImageTagHelper comment - #446 --- src/Jeebs.Mvc/TagHelpers/ImageTagHelper.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Jeebs.Mvc/TagHelpers/ImageTagHelper.cs b/src/Jeebs.Mvc/TagHelpers/ImageTagHelper.cs index a447ff9a0..e21d86642 100644 --- a/src/Jeebs.Mvc/TagHelpers/ImageTagHelper.cs +++ b/src/Jeebs.Mvc/TagHelpers/ImageTagHelper.cs @@ -1,4 +1,4 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; @@ -17,7 +17,8 @@ namespace Jeebs.Mvc.TagHelpers; public sealed class ImageTagHelper : UrlResolutionTagHelper { /// - /// Image src - if this starts '/' then it is assumed it is a path within the default wwwroot/images directory + /// Image src - if this starts '/' then it is assumed it is a path within the wwwroot/img directory - + /// otherwise use ~/... to reference an image elsewhere within wwwroot or an absolute URL /// public string Src { get; set; } = string.Empty; From cec9b63460e599bc0b5500241938f973b026b633 Mon Sep 17 00:00:00 2001 From: bfren Date: Fri, 19 May 2023 08:16:29 +0100 Subject: [PATCH 011/202] Updating packages --- Directory.Packages.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 46e0c58c2..d6d700275 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + @@ -27,9 +27,9 @@ - + - + @@ -37,7 +37,7 @@ - + @@ -53,7 +53,7 @@ - + From 80eee53da5f61ee9248e34efedc6c85660ca3f3f Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 13 Jul 2023 08:19:43 +0100 Subject: [PATCH 012/202] Adding VS Code solution supporty --- jeebs-v9.code-workspace | 1 + 1 file changed, 1 insertion(+) diff --git a/jeebs-v9.code-workspace b/jeebs-v9.code-workspace index 8a9e8007e..9f5a7075c 100644 --- a/jeebs-v9.code-workspace +++ b/jeebs-v9.code-workspace @@ -19,5 +19,6 @@ ".vscode/**": true, "docs/**": true, }, + "dotnet.defaultSolution": "Jeebs (v9).sln", } } \ No newline at end of file From 064329729d9c95ab13cff451f8420593d497d42e Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 13 Jul 2023 08:20:10 +0100 Subject: [PATCH 013/202] Bumping version to 9.0.0-beta.23071301 --- Version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version b/Version index 905c24392..4d66c0b5f 100644 --- a/Version +++ b/Version @@ -1 +1 @@ -8.3.1 \ No newline at end of file +9.0.0-beta.23071301 \ No newline at end of file From 9bd0a92a813c21c73513afa73232017cd9381e49 Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 13 Jul 2023 08:22:30 +0100 Subject: [PATCH 014/202] Updating packages --- Directory.Packages.props | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d6d700275..063eecc92 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,14 +8,14 @@ - - - - - - - - + + + + + + + + @@ -25,9 +25,9 @@ - + - + @@ -35,8 +35,8 @@ - - + + @@ -46,17 +46,17 @@ - - - - + + + + - - - - - - + + + + + + \ No newline at end of file From 2e321410a45666b4dc9359a86d70cad8d23afa5a Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 10 Aug 2023 06:54:31 +0100 Subject: [PATCH 015/202] Updating NuGet packages --- Directory.Packages.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0ba607abf..f223ed321 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,10 +12,10 @@ - - - - + + + + @@ -27,7 +27,7 @@ - + From 5bff697d184726e9105202a76c3d7946fa1097e5 Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 10 Aug 2023 07:35:15 +0100 Subject: [PATCH 016/202] Don't use tabs for all file types --- .editorconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index eb128c1da..9c23a43a5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -452,11 +452,15 @@ dotnet_naming_rule.parameters_rule.severity = warning ########################################## [*] -indent_style = tab + end_of_line = crlf [*.{cs,csx,cake,vb,vbx}] +indent_style = tab +indent_size = tab +tab_size = 4 + # SA1636: File header copyright text should match. dotnet_diagnostic.SA1636.severity = none From 3b89014bb680f87c9bb2adec8df059fb3e5434fc Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 10 Aug 2023 07:35:38 +0100 Subject: [PATCH 017/202] Updating packages --- Directory.Packages.props | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index f223ed321..7a89a2948 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,8 +10,8 @@ - - + + @@ -35,7 +35,7 @@ - + @@ -46,10 +46,10 @@ - - - - + + + + From 2f84f4e6196164b2baf2ec0784891419c1a312b0 Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 10 Oct 2023 09:44:07 +0100 Subject: [PATCH 018/202] Bumping version to 9.0.0-beta.203101001 --- Version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version b/Version index 4d66c0b5f..8e4ca5afe 100644 --- a/Version +++ b/Version @@ -1 +1 @@ -9.0.0-beta.23071301 \ No newline at end of file +9.0.0-beta.203101001 \ No newline at end of file From 6cbeed0bb446efa02b6c59703bca218c000b3080 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 28 Oct 2023 12:53:02 +0100 Subject: [PATCH 019/202] Updating packages --- Directory.Packages.props | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 1583bce0a..327b0e800 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,15 +7,15 @@ - + - - - - - - - + + + + + + + @@ -28,14 +28,14 @@ - + - + @@ -46,17 +46,17 @@ - - - - + + + + - + - - - + + + \ No newline at end of file From 5766c4b54e8d704760702d698ab266c986c22726 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 28 Oct 2023 12:54:17 +0100 Subject: [PATCH 020/202] Bumping version to 9.0.0-beta.23102801 --- Version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version b/Version index 8e4ca5afe..6e72d049d 100644 --- a/Version +++ b/Version @@ -1 +1 @@ -9.0.0-beta.203101001 \ No newline at end of file +9.0.0-beta.23102801 \ No newline at end of file From 7f3545c52efe46fa0fad44e6fcff3a31522ad193 Mon Sep 17 00:00:00 2001 From: bfren Date: Sun, 14 Jan 2024 08:22:56 +0000 Subject: [PATCH 021/202] Bumping version to 9.0.0-beta.24011401 --- Version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version b/Version index 6e72d049d..eef893e7e 100644 --- a/Version +++ b/Version @@ -1 +1 @@ -9.0.0-beta.23102801 \ No newline at end of file +9.0.0-beta.24011401 \ No newline at end of file From 4eddf5db01886b300fcca20f7f0c9dcfa26c368f Mon Sep 17 00:00:00 2001 From: bfren Date: Sun, 14 Jan 2024 08:30:32 +0000 Subject: [PATCH 022/202] Updating to .NET 8.0 --- src/Directory.Build.props | 152 +++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index dcd105094..9ece383a1 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,80 +1,80 @@ - - - net7.0 - latest - enable - + + + net8.0 + latest + enable + - - - - - - + + + + + + - - - true - + + + true + - - - - <_Parameter1>Tests.$(AssemblyName) - - + + + + <_Parameter1>Tests.$(AssemblyName) + + - - - $([MSBuild]::GetPathOfFileAbove('Jeebs (v9).sln')) - $([System.IO.Path]::GetDirectoryName('$(SolutionFilePath)')) - - - LICENSE - $([MSBuild]::GetPathOfFileAbove('$(LicenceFile)')) - Local.pack.props - $([MSBuild]::GetPathOfFileAbove('$(LocalPackFile)')) - logo.png - $([System.IO.Path]::Combine('$(SolutionRootPath)', 'artwork', '$(LogoFile)')) - README.md - $([MSBuild]::GetPathOfFileAbove('$(ReadmeFile)', '$(MSBuildProjectDirectory)')) - Version - $([MSBuild]::GetPathOfFileAbove('$(VersionFile)')) - + + + $([MSBuild]::GetPathOfFileAbove('Jeebs (v9).sln')) + $([System.IO.Path]::GetDirectoryName('$(SolutionFilePath)')) + + + LICENSE + $([MSBuild]::GetPathOfFileAbove('$(LicenceFile)')) + Local.pack.props + $([MSBuild]::GetPathOfFileAbove('$(LocalPackFile)')) + logo.png + $([System.IO.Path]::Combine('$(SolutionRootPath)', 'artwork', '$(LogoFile)')) + README.md + $([MSBuild]::GetPathOfFileAbove('$(ReadmeFile)', '$(MSBuildProjectDirectory)')) + Version + $([MSBuild]::GetPathOfFileAbove('$(VersionFile)')) + - - - - - - + + + + + + - - - $([System.IO.File]::ReadAllText('$(VersionPath)')) - + + + $([System.IO.File]::ReadAllText('$(VersionPath)')) + - - - bfren - bfren.dev - Copyright © bfren.dev 2013-$([System.DateTime]::Now.ToString(yyyy)) - embedded - $(MSBuildProjectName) library - $(LogoFile) - $(LicenceFile) - https://github.com/bfren/jeebs - $(ReadmeFile) - C#;Rapid Application Development;Toolkit - https://github.com/bfren/jeebs - git - $(JeebsVersion) - + + + bfren + bfren.dev + Copyright © bfren.dev 2013-$([System.DateTime]::Now.ToString(yyyy)) + embedded + $(MSBuildProjectName) library + $(LogoFile) + $(LicenceFile) + https://github.com/bfren/jeebs + $(ReadmeFile) + C#;Rapid Application Development;Toolkit + https://github.com/bfren/jeebs + git + $(JeebsVersion) + - - - - false - 8.3.0 - - - - - - + + + false + 8.4.0 + + + + + + From 304fd7ffee6bbb04c2bafc8cd3222f2008ccee44 Mon Sep 17 00:00:00 2001 From: bfren Date: Sun, 14 Jan 2024 08:30:36 +0000 Subject: [PATCH 023/202] Updating packages --- Directory.Packages.props | 81 ++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 327b0e800..8097480c0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,59 +4,60 @@ true - + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - - - + + + - + - + - + - - - - - - + + + + + + - - - - - + + + + + \ No newline at end of file From c187fdbcf51e8e5ae6f6086c93fe770e8425c617 Mon Sep 17 00:00:00 2001 From: bfren Date: Sat, 2 Mar 2024 17:22:17 +0000 Subject: [PATCH 024/202] Updating packages --- Directory.Packages.props | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8097480c0..648fad328 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,18 +4,18 @@ true - - - + + + - + - - - - - - + + + + + + @@ -27,16 +27,16 @@ - - - - + + + + - + - - + + @@ -47,17 +47,17 @@ - - - - + + + + - - - - - + + + + + \ No newline at end of file From d3b3b7330dfb8c691eacf3a3da0ba7d6a4773667 Mon Sep 17 00:00:00 2001 From: bfren Date: Thu, 21 Mar 2024 20:00:56 +0000 Subject: [PATCH 025/202] Updating packages --- Directory.Packages.props | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 648fad328..fc14237e5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,54 +8,54 @@ - - - - - - - - + + + + + + + + - + - + - + - + - + - - - - + + + + - - + + From ba275358d1538d8f6a1b0dd3b5245abc4dff3129 Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 26 Mar 2024 09:41:23 +0000 Subject: [PATCH 026/202] Switching base classes to use Wrap library --- src/Jeebs/ArrayExtensions.cs | 4 +- src/Jeebs/DateTimeInt.cs | 43 +++++++++++-------- src/Jeebs/Enumerated.cs | 26 ++--------- src/Jeebs/Jeebs.csproj | 1 - src/Jeebs/LogLevelExtensions.cs | 39 +++++++++++++++++ src/Jeebs/MaybeExtensions.Log.cs | 26 ----------- src/Jeebs/MaybeExtensions.LogAsync.cs | 18 -------- src/Jeebs/MaybeExtensions.LogBool.cs | 36 ---------------- src/Jeebs/MaybeExtensions.LogBoolAsync.cs | 18 -------- src/Jeebs/MimeType.cs | 2 +- src/Jeebs/ResultExtensions.Log.cs | 26 +++++++++++ src/Jeebs/ResultExtensions.LogAsync.cs | 18 ++++++++ src/Jeebs/ResultExtensions.LogBool.cs | 37 ++++++++++++++++ src/Jeebs/ResultExtensions.LogBoolAsync.cs | 18 ++++++++ ...MaybeExtensions.cs => ResultExtensions.cs} | 4 +- 15 files changed, 170 insertions(+), 146 deletions(-) create mode 100644 src/Jeebs/LogLevelExtensions.cs delete mode 100644 src/Jeebs/MaybeExtensions.Log.cs delete mode 100644 src/Jeebs/MaybeExtensions.LogAsync.cs delete mode 100644 src/Jeebs/MaybeExtensions.LogBool.cs delete mode 100644 src/Jeebs/MaybeExtensions.LogBoolAsync.cs create mode 100644 src/Jeebs/ResultExtensions.Log.cs create mode 100644 src/Jeebs/ResultExtensions.LogAsync.cs create mode 100644 src/Jeebs/ResultExtensions.LogBool.cs create mode 100644 src/Jeebs/ResultExtensions.LogBoolAsync.cs rename src/Jeebs/{MaybeExtensions.cs => ResultExtensions.cs} (61%) diff --git a/src/Jeebs/ArrayExtensions.cs b/src/Jeebs/ArrayExtensions.cs index b6f33f0d6..bac323398 100644 --- a/src/Jeebs/ArrayExtensions.cs +++ b/src/Jeebs/ArrayExtensions.cs @@ -1,8 +1,6 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System.Linq; - namespace Jeebs; /// @@ -23,6 +21,6 @@ public static T[] ExtendWith(this T[] @this, params T[] additionalItems) return @this; } - return @this.Concat(additionalItems).ToArray(); + return [.. @this, .. additionalItems]; } } diff --git a/src/Jeebs/DateTimeInt.cs b/src/Jeebs/DateTimeInt.cs index 4d4844535..35b5c11de 100644 --- a/src/Jeebs/DateTimeInt.cs +++ b/src/Jeebs/DateTimeInt.cs @@ -4,7 +4,6 @@ using System; using System.Globalization; using System.Linq; -using Jeebs.Messages; namespace Jeebs; @@ -13,10 +12,19 @@ namespace Jeebs; /// public sealed record class DateTimeInt { + /// + /// Twelve numbers: YYYYMMDDhhmm + /// private const string FormatString = "000000000000"; + /// + /// January, March, May, July, August, October, December + /// private static readonly int[] ThirtyOneDayMonths = [1, 3, 5, 7, 8, 10, 12]; + /// + /// April, June, September, November + /// private static readonly int[] ThirtyDayMonths = [4, 6, 9, 11]; /// @@ -96,14 +104,14 @@ public DateTimeInt(long value) /// /// Get the current DateTime /// - public Maybe ToDateTime() => + public Result ToDateTime() => IsValidDateTime() switch { { } x when x.Valid => new DateTime(Year, Month, Day, Hour, Minute, 0), { } x => - F.None(new M.InvalidDateTimeMsg((x.Part, this))) + Failures.InvalidDateTime(x.Part, this) }; /// @@ -151,15 +159,18 @@ public long ToLong() => return (false, nameof(Day)); } + // January, March, May, July, August, October, December if (ThirtyOneDayMonths.Contains(Month) && Day > 31) { return (false, nameof(Day)); } + // April, June, September, November else if (ThirtyDayMonths.Contains(Month) && Day > 30) { return (false, nameof(Day)); } - else // February is the only month left + // February + else { if (IsLeapYear(Year) && Day > 29) { @@ -241,20 +252,16 @@ private static (int year, int month, int day, int hour, int minute) Parse(string #endregion Static - /// Messages - public static class M + /// Failures. + public static class Failures { - /// Unable to parse DateTime integer - /// Invalid part and DateTimeInt - public sealed record class InvalidDateTimeMsg((string part, DateTimeInt dt) Value) : Msg - { - /// - public override string Format => - "Invalid {Part} - 'Y:{Year} M:{Month} D:{Day} H:{Hour} m:{Minute}'."; - - /// - public override object[]? Args => - new object[] { Value.part, Value.dt.Year, Value.dt.Month, Value.dt.Day, Value.dt.Hour, Value.dt.Minute }; - } + /// Unable to parse DateTime integer. + /// The name of the part that caused the error. + /// DateTime value. + public static Result InvalidDateTime(string part, DateTimeInt dt) => + R.Fail( + "Invalid {Part} - 'Y:{Year} M:{Month} D:{Day} H:{Hour} m:{Minute}'.", + part, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute + ); } } diff --git a/src/Jeebs/Enumerated.cs b/src/Jeebs/Enumerated.cs index bdfa9bbbd..d0018e4a1 100644 --- a/src/Jeebs/Enumerated.cs +++ b/src/Jeebs/Enumerated.cs @@ -4,7 +4,6 @@ using System; using System.Collections; using System.Collections.Concurrent; -using Jeebs.Messages; namespace Jeebs; @@ -82,7 +81,7 @@ internal static Maybe Check(string name, T value) value, false => - F.None(new M.NotAValidEnumeratedValueMsg(value)) + M.None }; /// @@ -107,7 +106,7 @@ protected static Maybe Parse(string name, T[] values) } // If we get here the name was never matched - return F.None(new M.NotAValidEnumeratedValueMsg(name)); + return M.None; }, new ParseArgs(name, values) ); @@ -120,7 +119,7 @@ protected static Maybe Parse(string name, T[] values) /// Enum values to check name against protected static bool IsRegistered(string name, T[] values) where T : Enumerated => - Parse(name, values).IsSome(out var _); + Parse(name, values).IsSome; /// /// Parse Arguments @@ -225,23 +224,4 @@ public int GetHashCode(IEqualityComparer comparer) => GetType().GetHashCode() ^ comparer.GetHashCode(name); #endregion Overrides - - /// Messages - public static class M - { - /// Value does not belong to the specified Enumerated type - /// Enum type - /// Value being parsed - public sealed record class NotAValidEnumeratedValueMsg(string Value) : Msg - where T : Enumerated - { - /// - public override string Format => - "'{Value}' is not a valid value of {Type}."; - - /// - public override object[]? Args => - new object[] { Value, typeof(T) }; - } - } } diff --git a/src/Jeebs/Jeebs.csproj b/src/Jeebs/Jeebs.csproj index 134efb967..98af0c01f 100644 --- a/src/Jeebs/Jeebs.csproj +++ b/src/Jeebs/Jeebs.csproj @@ -9,7 +9,6 @@ - diff --git a/src/Jeebs/LogLevelExtensions.cs b/src/Jeebs/LogLevelExtensions.cs new file mode 100644 index 000000000..9228100ec --- /dev/null +++ b/src/Jeebs/LogLevelExtensions.cs @@ -0,0 +1,39 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using MicrosoftLogLevel = Microsoft.Extensions.Logging.LogLevel; +using WrapLogLevel = Wrap.Logging.LogLevel; + +namespace Jeebs; + +public static class LogLevelExtensions +{ + /// + /// Convert a to a . + /// + /// value. + public static Maybe ToMicrosoft(this WrapLogLevel level) => + level switch + { + WrapLogLevel.Verbose => + MicrosoftLogLevel.Trace, + + WrapLogLevel.Debug => + MicrosoftLogLevel.Debug, + + WrapLogLevel.Information => + MicrosoftLogLevel.Information, + + WrapLogLevel.Warning => + MicrosoftLogLevel.Warning, + + WrapLogLevel.Error => + MicrosoftLogLevel.Error, + + WrapLogLevel.Fatal => + MicrosoftLogLevel.Critical, + + _ => + M.None + }; +} diff --git a/src/Jeebs/MaybeExtensions.Log.cs b/src/Jeebs/MaybeExtensions.Log.cs deleted file mode 100644 index ee85a6255..000000000 --- a/src/Jeebs/MaybeExtensions.Log.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using Jeebs.Logging; - -namespace Jeebs; - -public static partial class MaybeExtensions -{ - /// - public static Maybe Log(this Maybe @this, ILog usingLog) => - Log(@this, usingLog, "Done: {Value}."); - - /// - /// Log a result - or the reason if - /// - /// Maybe type - /// - /// - /// Log message - must contain one placeholder for the value. - public static Maybe Log(this Maybe @this, ILog usingLog, string message) => - @this.Audit( - some: x => usingLog.Inf(message, x ?? new object()), - none: usingLog.Msg - ); -} diff --git a/src/Jeebs/MaybeExtensions.LogAsync.cs b/src/Jeebs/MaybeExtensions.LogAsync.cs deleted file mode 100644 index 8f8b0687b..000000000 --- a/src/Jeebs/MaybeExtensions.LogAsync.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System.Threading.Tasks; -using Jeebs.Logging; - -namespace Jeebs; - -public static partial class MaybeExtensions -{ - /// - public static async Task> LogAsync(this Task> @this, ILog log) => - (await @this.ConfigureAwait(false)).Log(log, "Done: {Value}."); - - /// - public static async Task> LogAsync(this Task> @this, ILog log, string message) => - (await @this.ConfigureAwait(false)).Log(log, message); -} diff --git a/src/Jeebs/MaybeExtensions.LogBool.cs b/src/Jeebs/MaybeExtensions.LogBool.cs deleted file mode 100644 index 74f3b5ca6..000000000 --- a/src/Jeebs/MaybeExtensions.LogBool.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using Jeebs.Logging; - -namespace Jeebs; - -public static partial class MaybeExtensions -{ - /// - public static Maybe LogBool(this Maybe @this, ILog log) => - LogBool(@this, log, "Done.", "Failed."); - - /// - /// Log a boolean result - or the reason if - /// - /// - /// - /// Text on success - /// Text on failure - public static Maybe LogBool(this Maybe @this, ILog log, string done, string failed) => - @this.Audit( - some: x => - { - if (x) - { - log.Inf(done); - } - else - { - log.Err(failed); - } - }, - none: log.Msg - ); -} diff --git a/src/Jeebs/MaybeExtensions.LogBoolAsync.cs b/src/Jeebs/MaybeExtensions.LogBoolAsync.cs deleted file mode 100644 index 8bf69a654..000000000 --- a/src/Jeebs/MaybeExtensions.LogBoolAsync.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System.Threading.Tasks; -using Jeebs.Logging; - -namespace Jeebs; - -public static partial class MaybeExtensions -{ - /// - public static async Task> LogBoolAsync(this Task> @this, ILog log) => - (await @this.ConfigureAwait(false)).LogBool(log); - - /// - public static async Task> LogBoolAsync(this Task> @this, ILog log, string done, string failed) => - (await @this.ConfigureAwait(false)).LogBool(log, done, failed); -} diff --git a/src/Jeebs/MimeType.cs b/src/Jeebs/MimeType.cs index 7134baced..6dd5b68e6 100644 --- a/src/Jeebs/MimeType.cs +++ b/src/Jeebs/MimeType.cs @@ -126,7 +126,7 @@ public MimeType(string name) : base(name) { } /// Populate list of mime types /// static MimeType() => - All = new HashSet(new[] { Blank, General, Bmp, Doc, Docx, Gif, Jpg, M4a, Mp3, Pdf, Png, Ppt, Pptx, Rar, Tar, Text, Xls, Xlsx, Zip }); + All = new HashSet([Blank, General, Bmp, Doc, Docx, Gif, Jpg, M4a, Mp3, Pdf, Png, Ppt, Pptx, Rar, Tar, Text, Xls, Xlsx, Zip]); internal static HashSet AllTest() => All; diff --git a/src/Jeebs/ResultExtensions.Log.cs b/src/Jeebs/ResultExtensions.Log.cs new file mode 100644 index 000000000..e406b8a9f --- /dev/null +++ b/src/Jeebs/ResultExtensions.Log.cs @@ -0,0 +1,26 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using Jeebs.Logging; + +namespace Jeebs; + +public static partial class ResultExtensions +{ + /// + public static Result Log(this Result @this, ILog usingLog) => + Log(@this, usingLog, "Done: {Value}."); + + /// + /// Log a result - or the reason if . + /// + /// Ok value type. + /// Result object. + /// Log implementation. + /// Log message - must contain one placeholder for the value. + public static Result Log(this Result @this, ILog usingLog, string message) => + @this.Audit( + ok: x => usingLog.Inf(message, x ?? new object()), + fail: usingLog.Failure + ); +} diff --git a/src/Jeebs/ResultExtensions.LogAsync.cs b/src/Jeebs/ResultExtensions.LogAsync.cs new file mode 100644 index 000000000..85985e25b --- /dev/null +++ b/src/Jeebs/ResultExtensions.LogAsync.cs @@ -0,0 +1,18 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Threading.Tasks; +using Jeebs.Logging; + +namespace Jeebs; + +public static partial class ResultExtensions +{ + /// + public static async Task> LogAsync(this Task> @this, ILog log) => + (await @this.ConfigureAwait(false)).Log(log, "Done: {Value}."); + + /// + public static async Task> LogAsync(this Task> @this, ILog log, string message) => + (await @this.ConfigureAwait(false)).Log(log, message); +} diff --git a/src/Jeebs/ResultExtensions.LogBool.cs b/src/Jeebs/ResultExtensions.LogBool.cs new file mode 100644 index 000000000..d28fa5904 --- /dev/null +++ b/src/Jeebs/ResultExtensions.LogBool.cs @@ -0,0 +1,37 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using Jeebs.Logging; + +namespace Jeebs; + +public static partial class ResultExtensions +{ + /// + public static Result LogBool(this Result @this, ILog usingLog) => + LogBool(@this, usingLog, "Done.", "Failed."); + + /// + /// Log a boolean result - or the reason if . + /// + /// Ok value type. + /// Result object. + /// Log implementation. + /// Text when is and the value is true. + /// Text when is and the value is false. + public static Result LogBool(this Result @this, ILog usingLog, string ifTrue, string ifFalse) => + @this.Audit( + ok: x => + { + if (x) + { + usingLog.Inf(ifTrue); + } + else + { + usingLog.Err(ifFalse); + } + }, + fail: usingLog.Failure + ); +} diff --git a/src/Jeebs/ResultExtensions.LogBoolAsync.cs b/src/Jeebs/ResultExtensions.LogBoolAsync.cs new file mode 100644 index 000000000..bb17ed685 --- /dev/null +++ b/src/Jeebs/ResultExtensions.LogBoolAsync.cs @@ -0,0 +1,18 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Threading.Tasks; +using Jeebs.Logging; + +namespace Jeebs; + +public static partial class ResultExtensions +{ + /// + public static async Task> LogBoolAsync(this Task> @this, ILog log) => + (await @this.ConfigureAwait(false)).LogBool(log); + + /// + public static async Task> LogBoolAsync(this Task> @this, ILog log, string done, string failed) => + (await @this.ConfigureAwait(false)).LogBool(log, done, failed); +} diff --git a/src/Jeebs/MaybeExtensions.cs b/src/Jeebs/ResultExtensions.cs similarity index 61% rename from src/Jeebs/MaybeExtensions.cs rename to src/Jeebs/ResultExtensions.cs index 66cac0062..91abfd12a 100644 --- a/src/Jeebs/MaybeExtensions.cs +++ b/src/Jeebs/ResultExtensions.cs @@ -4,6 +4,6 @@ namespace Jeebs; /// -/// extension methods +/// extension methods. /// -public static partial class MaybeExtensions { } +public static partial class ResultExtensions { } From 93fdd341607355ddb098e2dc47707220ba8eefd8 Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 26 Mar 2024 09:41:32 +0000 Subject: [PATCH 027/202] Removing unnecessary Message classes --- src/Jeebs/Messages/ExceptionMsg.cs | 23 ----- src/Jeebs/Messages/Exceptions/MsgException.cs | 38 -------- src/Jeebs/Messages/INotFoundMsg.cs | 9 -- src/Jeebs/Messages/IWithValueMsg.cs | 21 ----- src/Jeebs/Messages/ListMsg.cs | 41 -------- src/Jeebs/Messages/Msg.cs | 93 ------------------- src/Jeebs/Messages/NotFoundMsg.cs | 8 -- src/Jeebs/Messages/WithInnerMsg.cs | 15 --- src/Jeebs/Messages/WithValueMsg.cs | 32 ------- 9 files changed, 280 deletions(-) delete mode 100644 src/Jeebs/Messages/ExceptionMsg.cs delete mode 100644 src/Jeebs/Messages/Exceptions/MsgException.cs delete mode 100644 src/Jeebs/Messages/INotFoundMsg.cs delete mode 100644 src/Jeebs/Messages/IWithValueMsg.cs delete mode 100644 src/Jeebs/Messages/ListMsg.cs delete mode 100644 src/Jeebs/Messages/Msg.cs delete mode 100644 src/Jeebs/Messages/NotFoundMsg.cs delete mode 100644 src/Jeebs/Messages/WithInnerMsg.cs delete mode 100644 src/Jeebs/Messages/WithValueMsg.cs diff --git a/src/Jeebs/Messages/ExceptionMsg.cs b/src/Jeebs/Messages/ExceptionMsg.cs deleted file mode 100644 index afb907e12..000000000 --- a/src/Jeebs/Messages/ExceptionMsg.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using Jeebs.Logging; - -namespace Jeebs.Messages; - -/// -public abstract record class ExceptionMsg : WithValueMsg, IExceptionMsg -{ - /// - /// Override Level with - /// - public override LogLevel Level => - LogLevel.Error; - - /// - /// Override Name with 'Exception' - /// - public override string Name => - nameof(Exception); -} diff --git a/src/Jeebs/Messages/Exceptions/MsgException.cs b/src/Jeebs/Messages/Exceptions/MsgException.cs deleted file mode 100644 index 535d360e6..000000000 --- a/src/Jeebs/Messages/Exceptions/MsgException.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; - -namespace Jeebs.Messages.Exceptions; - -/// -/// Throw an exception with an -/// -/// Reason type -public sealed class MsgException : Exception - where TMsg : IMsg -{ - /// - /// Create exception - /// - public MsgException() { } - - /// - /// Create exception - /// - /// - public MsgException(TMsg msg) : base(msg.ToString()) { } - - /// - /// Create exception - /// - /// Message - public MsgException(string message) : base(message) { } - - /// - /// Create exception - /// - /// Message - /// Inner Exception - public MsgException(string message, Exception innerException) : base(message, innerException) { } -} diff --git a/src/Jeebs/Messages/INotFoundMsg.cs b/src/Jeebs/Messages/INotFoundMsg.cs deleted file mode 100644 index 1acf37c43..000000000 --- a/src/Jeebs/Messages/INotFoundMsg.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Messages; - -/// -/// Framework 'Not Found' message -/// -public interface INotFoundMsg { } diff --git a/src/Jeebs/Messages/IWithValueMsg.cs b/src/Jeebs/Messages/IWithValueMsg.cs deleted file mode 100644 index 59ad4ab6f..000000000 --- a/src/Jeebs/Messages/IWithValueMsg.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Messages; - -/// -/// Framework message with a value -/// -/// Value type -public interface IWithValueMsg : IMsg -{ - /// - /// Message Value property name - /// - string Name { get; } - - /// - /// Message Value - /// - T Value { get; init; } -} diff --git a/src/Jeebs/Messages/ListMsg.cs b/src/Jeebs/Messages/ListMsg.cs deleted file mode 100644 index 2e6867735..000000000 --- a/src/Jeebs/Messages/ListMsg.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System.Collections.Generic; -using System.Linq; - -namespace Jeebs.Messages; - -/// -/// A message containing a list of other objects - useful for building multiple errors -/// -/// Message list -public sealed record class ListMsg(IList Messages) : Msg -{ - /// - /// Format messages one per line - /// - public override string Format => - "Messages: " + string.Join(System.Environment.NewLine, "{Msg}"); - - /// - /// Return messages as an array - /// - public override object[]? Args => - Messages.ToArray(); - - /// - /// Create with new messages - /// - /// Message list - public ListMsg(params IMsg[] msgs) : this(msgs.ToList()) { } - - /// - /// Add a message to the list - /// - /// Message type - /// Message - public void Add(T msg) - where T : IMsg => - Messages.Add(msg); -} diff --git a/src/Jeebs/Messages/Msg.cs b/src/Jeebs/Messages/Msg.cs deleted file mode 100644 index 0bf080db5..000000000 --- a/src/Jeebs/Messages/Msg.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System.Collections.Generic; -using System.Linq; -using Jeebs.Functions; -using Jeebs.Logging; -using Jeebs.Messages.Exceptions; - -namespace Jeebs.Messages; - -/// -/// Framework message - compatible with -/// -public abstract record class Msg() : IMsg -{ - /// - /// Default LogLevel for messages - /// - public static readonly LogLevel DefaultLevel = - LogLevel.Warning; - - /// - public virtual LogLevel Level => - level ?? DefaultLevel; - - private readonly LogLevel? level; - - /// - public virtual string Format => - format ?? string.Empty; - - private readonly string? format; - - /// - public string FormatWithType => - $"{{MsgType}} {Format}".Trim(); - - /// - public virtual object[]? Args => - args; - - private readonly object[]? args; - - /// - public object[] ArgsWithType - { - get - { - // Add type to list of arguments - var list = Args?.ToList() ?? []; - list.Insert(0, GetTypeName()); - - // Return as array - return list.ToArray(); - } - } - - /// - /// For testing, allow , , and to be set via constructor - /// - /// Log Level - /// Format - /// - private protected Msg(LogLevel? level, string? format, object[]? args) : this() => - (this.level, this.format, this.args) = (level, format, args); - - /// - public string GetTypeName() => - GetType().ToString(); - - /// - /// Override using formatted message - /// - public sealed override string ToString() => - string.IsNullOrWhiteSpace(Format) switch - { - true => - GetTypeName(), - - false => - StringF.Format(FormatWithType, ArgsWithType) - }; - - /// - /// Create - /// - /// Message type - /// Message - public static MsgException CreateException(TMsg msg) - where TMsg : IMsg => - new(msg); -} diff --git a/src/Jeebs/Messages/NotFoundMsg.cs b/src/Jeebs/Messages/NotFoundMsg.cs deleted file mode 100644 index 213968a7e..000000000 --- a/src/Jeebs/Messages/NotFoundMsg.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Messages; - -/// -/// Value type -public abstract record class NotFoundMsg : WithValueMsg, INotFoundMsg; diff --git a/src/Jeebs/Messages/WithInnerMsg.cs b/src/Jeebs/Messages/WithInnerMsg.cs deleted file mode 100644 index 80fbc5783..000000000 --- a/src/Jeebs/Messages/WithInnerMsg.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Messages; - -/// -/// Wrapper that contains an inner message -/// -/// Inner Message -public abstract record class WithInnerMsg(IMsg Value) : WithValueMsg -{ - /// - public override string Name => - "Inner Message"; -} diff --git a/src/Jeebs/Messages/WithValueMsg.cs b/src/Jeebs/Messages/WithValueMsg.cs deleted file mode 100644 index ff8de98c2..000000000 --- a/src/Jeebs/Messages/WithValueMsg.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Messages; - -/// -public abstract record class WithValueMsg() : Msg, IWithValueMsg -{ - /// - public virtual string Name => - name ?? nameof(Value); - - private readonly string? name; - - /// - public abstract T Value { get; init; } - - /// - public sealed override string Format => - $"{Name} = {{Value}}"; - - /// - public sealed override object[]? Args => - new[] { Value ?? new object() }; - - /// - /// For testing, allow to be set via constructor - /// - /// Value name - private protected WithValueMsg(string name) : this() => - this.name = name; -} From 4009c0c05f57af1a090cbeb958bb7e3652299561 Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 26 Mar 2024 09:41:41 +0000 Subject: [PATCH 028/202] Switching Logging classes to use Wrap library --- src/Jeebs/Logging/ILog.cs | 81 +++++++++++++++---------------- src/Jeebs/Logging/Log.cs | 41 +++++----------- src/Jeebs/Logging/LogLevel.cs | 51 ------------------- src/Jeebs/Logging/NullLogger.cs | 3 +- src/Jeebs/Logging/StaticLogger.cs | 10 ++-- 5 files changed, 59 insertions(+), 127 deletions(-) delete mode 100644 src/Jeebs/Logging/LogLevel.cs diff --git a/src/Jeebs/Logging/ILog.cs b/src/Jeebs/Logging/ILog.cs index ec92f004a..e72651484 100644 --- a/src/Jeebs/Logging/ILog.cs +++ b/src/Jeebs/Logging/ILog.cs @@ -2,101 +2,98 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; +using Wrap.Logging; namespace Jeebs.Logging; /// -/// Enables agnostic logging operations +/// Enables agnostic logging operations. /// -/// Log context +/// Log context. public interface ILog : ILog { } /// -/// Enables agnostic logging operations +/// Enables agnostic logging operations. /// public interface ILog { /// - /// Return a new log instance for a different context + /// Return a new log instance for a different context. /// - /// Log context + /// Log context. ILog ForContext(); /// - /// Whether or not the log will write for the specified Level + /// Whether or not the log will write for the specified Level. /// - /// LogLevel + /// LogLevel. bool IsEnabled(LogLevel level); /// - /// Whether or not the log will write for the specified Level + /// Whether or not the log will write for the specified Level. /// - /// LogLevel + /// LogLevel. bool IsEnabled(Microsoft.Extensions.Logging.LogLevel level); /// - /// Log an using the it defines, - /// or + /// Log a using the it defines, + /// or . /// - /// Message type - /// Message to log - void Msg(T? message) - where T : IMsg; + /// Failure to log. + void Failure(FailValue failure); /// - /// Log an using the specified + /// Log a using the specified . /// - /// Message type - /// Message to log - /// Log level - void Msg(T? message, LogLevel level) - where T : IMsg; + /// Failure to log. + /// Log level. + void Failure(FailValue failure, LogLevel level); /// - /// Log a list of + /// Log an array of values. /// - /// Messages to log - void Msgs(params IMsg[] messages); + /// Failures to log. + void Failures(params FailValue[] failures); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Vrb(string message, params object[] args); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Dbg(string message, params object[] args); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Inf(string message, params object[] args); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Wrn(string message, params object[] args); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Err(string message, params object[] args); /// - /// Exception - /// Message - /// Arguments (if message supports string.Format()) + /// Exception. + /// Message. + /// Arguments (if message supports string.Format()). void Err(Exception ex, string message, params object[] args); /// - /// Message - /// Arguments (if message supports string.Format()) + /// Message. + /// Arguments (if message supports string.Format()). void Ftl(string message, params object[] args); /// - /// Exception - /// Message - /// Arguments (if message supports string.Format()) + /// Exception. + /// Message. + /// Arguments (if message supports string.Format()). void Ftl(Exception ex, string message, params object[] args); } diff --git a/src/Jeebs/Logging/Log.cs b/src/Jeebs/Logging/Log.cs index 1eddfba55..9dae98dd8 100644 --- a/src/Jeebs/Logging/Log.cs +++ b/src/Jeebs/Logging/Log.cs @@ -2,7 +2,7 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; -using Jeebs.Messages; +using Wrap.Logging; namespace Jeebs.Logging; @@ -13,35 +13,20 @@ public abstract class Log : ILog public abstract ILog ForContext(); /// - public void Msg(T? message) - where T : IMsg => - Msg(message, message switch - { - Msg msg => - msg.Level, - - _ => - Messages.Msg.DefaultLevel - }); + public void Failure(FailValue failure) => + Failure(failure, failure.Level); /// - public void Msg(T? message, LogLevel level) - where T : IMsg + public void Failure(FailValue failure, LogLevel level) { - // Get message text and arguments - var (text, args) = message switch + // Get failure message and arguments + var (text, args) = failure.Context switch { - Msg msg => - ( - msg.FormatWithType, - msg.ArgsWithType - ), + string context => + ("{Context} | " + failure.Message, [context, .. failure.Args]), _ => - ( - message?.ToString() ?? typeof(T).ToString(), - Array.Empty() - ), + (failure.Message, failure.Args ?? []) }; // Switch different levels @@ -73,16 +58,16 @@ public void Msg(T? message, LogLevel level) } /// - public void Msgs(params IMsg[] messages) + public void Failures(params FailValue[] failures) { - if (messages.Length == 0) + if (failures.Length == 0) { return; } - foreach (var m in messages) + foreach (var f in failures) { - Msg(m); + Failure(f); } } diff --git a/src/Jeebs/Logging/LogLevel.cs b/src/Jeebs/Logging/LogLevel.cs deleted file mode 100644 index 03315a036..000000000 --- a/src/Jeebs/Logging/LogLevel.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Logging; - -/// -/// Log Levels - descriptions taken from https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.loglevel?view=dotnet-plat-ext-5.0 -/// -public enum LogLevel -{ - /// - /// Unknown log level - will use default - /// - Unknown = 0, - - /// - /// Logs that contain the most detailed messages. - /// These messages may contain sensitive application data. - /// These messages are disabled by default and should never be enabled in a production environment. - /// - Verbose = 1 << 0, - - /// - /// Logs that are used for interactive investigation during development. - /// These logs should primarily contain information useful for debugging and have no long-term value. - /// - Debug = 1 << 1, - - /// - /// Logs that track the general flow of the application. These logs should have long-term value. - /// - Information = 1 << 2, - - /// - /// Logs that highlight an abnormal or unexpected event in the application flow, - /// but do not otherwise cause the application execution to stop. - /// - Warning = 1 << 3, - - /// - /// Logs that highlight when the current flow of execution is stopped due to a failure. - /// These should indicate a failure in the current activity, not an application-wide failure. - /// - Error = 1 << 4, - - /// - /// Logs that describe an unrecoverable application or system crash, - /// or a catastrophic failure that requires immediate attention. - /// - Fatal = 1 << 5 -} diff --git a/src/Jeebs/Logging/NullLogger.cs b/src/Jeebs/Logging/NullLogger.cs index c15da40fe..6ad4e96d8 100644 --- a/src/Jeebs/Logging/NullLogger.cs +++ b/src/Jeebs/Logging/NullLogger.cs @@ -2,6 +2,7 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; +using Wrap.Logging; namespace Jeebs.Logging; @@ -9,7 +10,7 @@ namespace Jeebs.Logging; public sealed class NullLogger : NullLogger, ILog { } /// -/// A logger that does nothing - except stop null reference exceptions when using the static logger +/// A logger that does nothing - except stop null reference exceptions when using the static logger. /// public class NullLogger : Log { diff --git a/src/Jeebs/Logging/StaticLogger.cs b/src/Jeebs/Logging/StaticLogger.cs index 318db016c..5693e4de2 100644 --- a/src/Jeebs/Logging/StaticLogger.cs +++ b/src/Jeebs/Logging/StaticLogger.cs @@ -6,25 +6,25 @@ namespace Jeebs.Logging; /// -/// Used to access logging functionality when dependency injection is not available +/// Used to access logging functionality when dependency injection is not available. /// public static class StaticLogger { /// - /// Factory to create a static logger + /// Factory to create a static logger. /// public static Lazy Factory { private get; set; } = new(new NullLogger()); /// - /// Return a new logger + /// Return a new logger. /// public static ILog Log => Factory.Value; /// - /// Return a new log instance for a specific context + /// Return a new log instance for a specific context. /// - /// Log context type + /// Log context type. public static ILog ForContext() => Factory.Value.ForContext(); } From c61ce4eeffbe0d6afb94fb17e897c45d81601fdd Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 26 Mar 2024 09:41:51 +0000 Subject: [PATCH 029/202] Switching Functions classes to use Wrap library --- .../Functions/Base32F.FromBase32String.cs | 25 ++-- src/Jeebs/Functions/Base32F.ToBase32String.cs | 4 +- src/Jeebs/Functions/Base32F.cs | 17 +-- src/Jeebs/Functions/BooleanF.Parse.cs | 28 +--- src/Jeebs/Functions/DateTimeF.FromFormat.cs | 16 +-- src/Jeebs/Functions/DateTimeF.FromUnix.cs | 4 +- src/Jeebs/Functions/DateTimeF.UnixEpoch.cs | 2 +- src/Jeebs/Functions/DateTimeF.cs | 8 +- src/Jeebs/Functions/EnumF.Convert.cs | 121 +++++------------- src/Jeebs/Functions/EnumF.Parse.cs | 24 ++-- src/Jeebs/Functions/EnumF.cs | 8 +- src/Jeebs/Functions/JsonF.Bool.cs | 4 +- src/Jeebs/Functions/JsonF.CopyOptions.cs | 2 +- src/Jeebs/Functions/JsonF.Deserialise.cs | 29 ++--- src/Jeebs/Functions/JsonF.Serialise.cs | 32 +---- src/Jeebs/Functions/JsonF.cs | 15 +-- .../LogLevelF.ConvertToMicrosoftLevel.cs | 47 ------- src/Jeebs/Functions/LogLevelF.cs | 13 -- src/Jeebs/Functions/MathsF.Combinations.cs | 12 +- src/Jeebs/Functions/MathsF.Factorial.cs | 6 +- src/Jeebs/Functions/MathsF.Permutations.cs | 10 +- src/Jeebs/Functions/MathsF.cs | 6 +- src/Jeebs/Functions/PhpF.Deserialise.cs | 8 +- src/Jeebs/Functions/PhpF.Serialise.cs | 6 +- src/Jeebs/Functions/PhpF.cs | 2 +- src/Jeebs/Functions/StringF.Format.cs | 35 +++-- src/Jeebs/Functions/ThreadF.FireAndForget.cs | 16 +-- .../TypeF.GetPropertyTypesImplementing.cs | 8 +- ...peF.GetPropertyTypesImplementingGeneric.cs | 6 +- .../Functions/TypeF.GetTypesImplementing.cs | 8 +- .../TypeF.GetTypesImplementingGeneric.cs | 6 +- src/Jeebs/Functions/TypeF.cs | 10 +- src/Jeebs/Functions/UriF.IsHttp.cs | 14 +- .../VersionF.GetJeebsVersionAsync.cs | 11 +- src/Jeebs/Functions/VersionF.GetVersion.cs | 10 +- src/Jeebs/Functions/VersionF.cs | 6 +- 36 files changed, 191 insertions(+), 388 deletions(-) delete mode 100644 src/Jeebs/Functions/LogLevelF.ConvertToMicrosoftLevel.cs delete mode 100644 src/Jeebs/Functions/LogLevelF.cs diff --git a/src/Jeebs/Functions/Base32F.FromBase32String.cs b/src/Jeebs/Functions/Base32F.FromBase32String.cs index a350f304c..b58b4ed4f 100644 --- a/src/Jeebs/Functions/Base32F.FromBase32String.cs +++ b/src/Jeebs/Functions/Base32F.FromBase32String.cs @@ -2,18 +2,20 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; -using Jeebs.Messages; namespace Jeebs.Functions; public static partial class Base32F { /// - /// Convert string to a byte array + /// Convert string to a byte array. /// - /// Base32 string to convert - must be at least two characters - public static Maybe FromBase32String(string base32String) + /// Base32 string to convert - must be at least two characters. + public static Result FromBase32String(string base32String) { + static Result fail(string message, params object[] args) => + R.Fail(nameof(Base32F), nameof(FromBase32String), message, args); + // Check if string is empty if (string.IsNullOrEmpty(base32String)) { @@ -29,7 +31,7 @@ public static Maybe FromBase32String(string base32String) // Check the size if (outputBytes.Length == 0) { - return F.None(); + return fail("Input string is not long enough."); } // Position in the string @@ -54,7 +56,7 @@ public static Maybe FromBase32String(string base32String) // Check if found if (currentBase32Byte < 0) { - return F.None(new M.CharacterNotInBase32AlphabetMsg(base32String[base32Position])); + return fail("'{Character}' is not in Base32 alphabet.", base32String[base32Position]); } // Calculate the number of bits we can extract out of current input character to fill missing bits in the output byte @@ -91,15 +93,4 @@ public static Maybe FromBase32String(string base32String) return outputBytes; } - - /// Messages - public static partial class M - { - /// Input string is not long enough to construct a complete byte array - public sealed record class InputStringNotLongEnoughMsg : Msg; - - /// Input string contains a character that is not in the Base32 alphabet - /// Invalid character - public sealed record class CharacterNotInBase32AlphabetMsg(char Value) : WithValueMsg; - } } diff --git a/src/Jeebs/Functions/Base32F.ToBase32String.cs b/src/Jeebs/Functions/Base32F.ToBase32String.cs index 2673e08ba..db18ee497 100644 --- a/src/Jeebs/Functions/Base32F.ToBase32String.cs +++ b/src/Jeebs/Functions/Base32F.ToBase32String.cs @@ -9,9 +9,9 @@ namespace Jeebs.Functions; public static partial class Base32F { /// - /// Convert to a Base32 string + /// Convert to a Base32 string. /// - /// Input byte array + /// Input byte array. public static string ToBase32String(byte[] bytes) { // Check if byte array is null diff --git a/src/Jeebs/Functions/Base32F.cs b/src/Jeebs/Functions/Base32F.cs index f8d141216..928b6f5b5 100644 --- a/src/Jeebs/Functions/Base32F.cs +++ b/src/Jeebs/Functions/Base32F.cs @@ -4,28 +4,25 @@ namespace Jeebs.Functions; /// -/// C# Base32 Converter -/// Copyright (c) 2014 Oleg Ignat - licensed under https://creativecommons.org/licenses/by/2.0/ -/// See https://olegignat.com/base32/ -/// Modifications to make consistent with Jeebs coding style and conventions (c) bfren as above +/// C# Base32 Converter.
+/// Copyright (c) 2014 Oleg Ignat - licensed under https://creativecommons.org/licenses/by/2.0/
+/// See https://olegignat.com/base32/
+/// Modifications to make consistent with Jeebs coding style and conventions (c) bfren as above. ///
public static partial class Base32F { /// - /// Size of the regular byte in bits + /// Size of the regular byte in bits. /// private const int InByteSize = 8; /// - /// Size of converted byte in bits + /// Size of converted byte in bits. /// private const int OutByteSize = 5; /// - /// Alphabet - see https://datatracker.ietf.org/doc/html/rfc3548#section-5 + /// Alphabet - see https://datatracker.ietf.org/doc/html/rfc3548#section-5. /// private const string Base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - - /// Messages - public static partial class M { } } diff --git a/src/Jeebs/Functions/BooleanF.Parse.cs b/src/Jeebs/Functions/BooleanF.Parse.cs index f3327164f..30dcf1ead 100644 --- a/src/Jeebs/Functions/BooleanF.Parse.cs +++ b/src/Jeebs/Functions/BooleanF.Parse.cs @@ -3,27 +3,26 @@ using System.Globalization; using System.Linq; -using Jeebs.Messages; namespace Jeebs.Functions; /// -/// Boolean functions +/// Boolean functions. /// public static class BooleanF { /// - /// Parse a boolean value + /// Parse a boolean value. /// - /// Value type - /// Value to parse + /// Value type. + /// Value to parse. public static Maybe Parse(T value) { // Convert to string var val = value?.ToString()?.ToLower(CultureInfo.InvariantCulture); if (val is null) { - return F.None(); + return M.None; } // Alternative boolean values @@ -40,20 +39,7 @@ public static Maybe Parse(T value) return false; } - return F.ParseBool(val).Switch( - some: x => F.Some(x), - none: _ => F.None(new M.UnrecognisedValueMsg(val)) - ); - } - - /// Messages - public static class M - { - /// Null Value - public sealed record class NullValueMsg : Msg; - - /// Unrecognised boolean value - /// Unrecognised Value - public sealed record class UnrecognisedValueMsg(string Value) : WithValueMsg(); + // Parse default values + return M.ParseBool(val); } } diff --git a/src/Jeebs/Functions/DateTimeF.FromFormat.cs b/src/Jeebs/Functions/DateTimeF.FromFormat.cs index c933703d2..d227ed1f1 100644 --- a/src/Jeebs/Functions/DateTimeF.FromFormat.cs +++ b/src/Jeebs/Functions/DateTimeF.FromFormat.cs @@ -3,17 +3,16 @@ using System; using System.Globalization; -using Jeebs.Messages; namespace Jeebs.Functions; public static partial class DateTimeF { /// - /// Create a DateTime object from a given format + /// Create a DateTime object from a given format. /// - /// Input string - /// DateTime format + /// Input string. + /// DateTime format. public static Maybe FromFormat(string s, string format) { if (DateTime.TryParseExact(s, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt)) @@ -21,13 +20,6 @@ public static Maybe FromFormat(string s, string format) return dt; } - return F.None(new M.InvalidDateTimeMsg(s)); - } - - public static partial class M - { - /// Unable to parse DateTime string - /// DateTime string - public sealed record class InvalidDateTimeMsg(string Value) : WithValueMsg; + return M.None; } } diff --git a/src/Jeebs/Functions/DateTimeF.FromUnix.cs b/src/Jeebs/Functions/DateTimeF.FromUnix.cs index 95884c70f..660b43aa5 100644 --- a/src/Jeebs/Functions/DateTimeF.FromUnix.cs +++ b/src/Jeebs/Functions/DateTimeF.FromUnix.cs @@ -8,9 +8,9 @@ namespace Jeebs.Functions; public static partial class DateTimeF { /// - /// Convert a Unix timestamp to a DateTime object + /// Convert a Unix timestamp to a DateTime object. /// - /// Unix timestamp (in seconds) + /// Unix timestamp (in seconds). public static DateTime FromUnix(double unixTimeStampInSeconds) => DateTime.UnixEpoch.AddSeconds(unixTimeStampInSeconds).ToUniversalTime(); } diff --git a/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs b/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs index 804ab032d..90bb5bdcc 100644 --- a/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs +++ b/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs @@ -8,7 +8,7 @@ namespace Jeebs.Functions; public static partial class DateTimeF { /// - /// Returns a DateTime object representing the start of the Unix Epoch + /// Returns a DateTime object representing the start of the Unix Epoch. /// public static DateTime UnixEpoch() => new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); diff --git a/src/Jeebs/Functions/DateTimeF.cs b/src/Jeebs/Functions/DateTimeF.cs index 3ac29b91c..31116170e 100644 --- a/src/Jeebs/Functions/DateTimeF.cs +++ b/src/Jeebs/Functions/DateTimeF.cs @@ -4,10 +4,6 @@ namespace Jeebs.Functions; /// -/// DateTime functions +/// DateTime functions. /// -public static partial class DateTimeF -{ - /// Messages - public static partial class M { } -} +public static partial class DateTimeF { } diff --git a/src/Jeebs/Functions/EnumF.Convert.cs b/src/Jeebs/Functions/EnumF.Convert.cs index de768c446..35c8d2f3f 100644 --- a/src/Jeebs/Functions/EnumF.Convert.cs +++ b/src/Jeebs/Functions/EnumF.Convert.cs @@ -3,117 +3,58 @@ using System; using System.Globalization; -using Jeebs.Messages; namespace Jeebs.Functions; public static partial class EnumF { /// - /// Parse an integer value into the specified Enum - /// Throws - /// KeyNotFoundException when the value does not exist in the specified Enum type + /// Parse an integer value into the specified Enum.
///
- /// Enum type - /// The value to parse + /// Enum type. + /// The value to parse. public static FluentConvert Convert(TFrom value) where TFrom : struct, Enum => new(value); /// - /// FluentConvert + /// FluentConvert. /// - /// Convert from type - public sealed class FluentConvert + /// Convert from type. + /// Convert from value. + public sealed class FluentConvert(TFrom from) where TFrom : struct, Enum { - private readonly TFrom from; + private readonly TFrom from = from; /// - /// Construct object + /// Convert value to specified type. /// - /// Convert from type - public FluentConvert(TFrom from) => - this.from = from; - - /// - /// Convert value to specified type - /// - /// Convert To type - public Maybe To() + /// Convert To type. + public Result To() where TTo : struct, Enum { - // Convert to long so we can get the value of the receiving enum - var fromLong = System.Convert.ChangeType(from, typeof(long), CultureInfo.InvariantCulture); - - // Convert to receiving Enum - if fromLong is not defined in TTo, Enum.ToObject() will return - // fromLong, rather than the Enum value, so we also need to check the parsed object exists in - // TTo before returning it - return Enum.ToObject(typeof(TTo), fromLong) switch + try { - TTo x when Enum.IsDefined(typeof(TTo), x) => - x, - - _ => - F.None(new M.ValueNotInReceivingEnumMsg(from)) - }; - } - } - - /// Messages - public static partial class M - { - /// Type is not a valid - /// Enum type - public sealed record class NotAValidEnumMsg(Type Value) : WithValueMsg; - - /// Attempting to parse a null value - public sealed record class NullValueMsg : Msg; - - /// is not a valid value of - /// Enum type - /// Enum value - public sealed record class NotAValidEnumValueMsg(string Value) : Msg - where T : struct, Enum - { - /// - public override string Format => - "'{Value}' is not a valid value of {Type}."; - - /// - public override object[]? Args => - new object[] { Value, typeof(T) }; - } - - /// is not a valid value of - /// Enum type - /// Enum value - public sealed record class NotAValidEnumValueMsg(Type EnumType, string Value) : Msg - { - /// - public override string Format => - "'{Value}' is not a valid value of {Type}."; - - /// - public override object[]? Args => - new object[] { Value, EnumType }; - } - - /// is not in - /// From Enum - /// To Enum - /// From Enum value - public sealed record class ValueNotInReceivingEnumMsg(TFrom Value) : Msg - where TFrom : struct, Enum - where TTo : struct, Enum - { - /// - public override string Format => - "'{Value}' is not a valid {Type}."; - - /// - public override object[]? Args => - new object[] { Value, typeof(TTo) }; + // Convert to long so we can get the value of the receiving enum + var fromLong = System.Convert.ChangeType(from, typeof(long), CultureInfo.InvariantCulture); + + // Convert to receiving Enum - if fromLong is not defined in TTo, Enum.ToObject() will return + // fromLong, rather than the Enum value, so we also need to check the parsed object exists in + // TTo before returning it + return Enum.ToObject(typeof(TTo), fromLong) switch + { + TTo x when Enum.IsDefined(typeof(TTo), x) => + x, + + _ => + R.Fail(nameof(FluentConvert), nameof(To), "Unable to convert {From} to type {To}.", from, typeof(TTo)) + }; + } + catch (Exception ex) + { + return R.Fail(ex); + } } } } diff --git a/src/Jeebs/Functions/EnumF.Parse.cs b/src/Jeebs/Functions/EnumF.Parse.cs index cf57256f3..f60926154 100644 --- a/src/Jeebs/Functions/EnumF.Parse.cs +++ b/src/Jeebs/Functions/EnumF.Parse.cs @@ -8,16 +8,16 @@ namespace Jeebs.Functions; public static partial class EnumF { /// - /// Parse a string value into the specified Enum + /// Parse a string value into the specified Enum. /// - /// Enum type - /// The value to parse + /// Enum type. + /// The value to parse. public static Maybe Parse(string? value) where T : struct, Enum { if (value is null) { - return F.None(); + return M.None; } try @@ -28,30 +28,30 @@ public static Maybe Parse(string? value) x, _ => - F.None(new M.NotAValidEnumValueMsg(value)) + M.None }; } catch (Exception) { - return F.None(new M.NotAValidEnumValueMsg(value)); + return M.None; } } /// - /// Parse a string value into the specified Enum + /// Parse a string value into the specified Enum. /// - /// Enum type - /// The value to parse + /// Enum type. + /// The value to parse. public static Maybe Parse(Type t, string? value) { if (!t.IsEnum) { - return F.None(new M.NotAValidEnumMsg(t)); + return M.None; } if (value is null) { - return F.None(); + return M.None; } try @@ -60,7 +60,7 @@ public static Maybe Parse(Type t, string? value) } catch (Exception) { - return F.None(new M.NotAValidEnumValueMsg(t, value)); + return M.None; } } } diff --git a/src/Jeebs/Functions/EnumF.cs b/src/Jeebs/Functions/EnumF.cs index 6123025e3..4c8a1fbad 100644 --- a/src/Jeebs/Functions/EnumF.cs +++ b/src/Jeebs/Functions/EnumF.cs @@ -4,10 +4,6 @@ namespace Jeebs.Functions; /// -/// Enum functions +/// Enum functions. /// -public static partial class EnumF -{ - /// Messages - public static partial class M { } -} +public static partial class EnumF { } diff --git a/src/Jeebs/Functions/JsonF.Bool.cs b/src/Jeebs/Functions/JsonF.Bool.cs index ebee08a67..482fc8476 100644 --- a/src/Jeebs/Functions/JsonF.Bool.cs +++ b/src/Jeebs/Functions/JsonF.Bool.cs @@ -6,9 +6,9 @@ namespace Jeebs.Functions; public static partial class JsonF { /// - /// Return lower-case boolean string + /// Return lower-case boolean string. /// - /// Value + /// Boolean value. public static string Bool(bool value) => value switch { diff --git a/src/Jeebs/Functions/JsonF.CopyOptions.cs b/src/Jeebs/Functions/JsonF.CopyOptions.cs index bca3518a4..52bdcae3d 100644 --- a/src/Jeebs/Functions/JsonF.CopyOptions.cs +++ b/src/Jeebs/Functions/JsonF.CopyOptions.cs @@ -8,7 +8,7 @@ namespace Jeebs.Functions; public static partial class JsonF { /// - /// Get a copy of the default serialiser options + /// Get a copy of the default serialiser options. /// public static JsonSerializerOptions CopyOptions() { diff --git a/src/Jeebs/Functions/JsonF.Deserialise.cs b/src/Jeebs/Functions/JsonF.Deserialise.cs index 361b2c836..53bfa0ad7 100644 --- a/src/Jeebs/Functions/JsonF.Deserialise.cs +++ b/src/Jeebs/Functions/JsonF.Deserialise.cs @@ -3,24 +3,26 @@ using System; using System.Text.Json; -using Jeebs.Messages; namespace Jeebs.Functions; public static partial class JsonF { /// - /// Use JsonSerializer to deserialise a given string into a given object type + /// Use JsonSerializer to deserialise a given string into a given object type. /// - /// The type of the object to return - /// The string to deserialise - /// JsonSerializerOptions - public static Maybe Deserialise(string str, JsonSerializerOptions options) + /// The type of the object to return. + /// The string to deserialise. + /// JsonSerializerOptions. + public static Result Deserialise(string str, JsonSerializerOptions options) { + static Result fail(string message) => + R.Fail(nameof(JsonF), nameof(Deserialise), message); + // Check for null string if (str is null || string.IsNullOrWhiteSpace(str)) { - return F.None(); + return fail("Cannot deserialise a null or empty string to JSON."); } // Attempt to deserialise JSON @@ -32,23 +34,16 @@ public static Maybe Deserialise(string str, JsonSerializerOptions options) x, _ => - F.None() // should never get here + fail("Json deserialise returned a null object.") // should never get here }; } catch (Exception ex) { - return F.None(new M.DeserialiseExceptionMsg(ex)); + return R.Fail(nameof(JsonF), nameof(Deserialise), ex); } } /// - public static Maybe Deserialise(string str) => + public static Result Deserialise(string str) => Deserialise(str, Options); - - public static partial class M - { - /// Exception caught during - /// Exception object - public sealed record class SerialiseExceptionMsg(Exception Value) : ExceptionMsg; - } } diff --git a/src/Jeebs/Functions/JsonF.Serialise.cs b/src/Jeebs/Functions/JsonF.Serialise.cs index 6a1552a4e..7956b6fed 100644 --- a/src/Jeebs/Functions/JsonF.Serialise.cs +++ b/src/Jeebs/Functions/JsonF.Serialise.cs @@ -1,47 +1,29 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System; using System.Text.Json; -using Jeebs.Messages; namespace Jeebs.Functions; public static partial class JsonF { /// - /// Use JsonSerializer to serialise a given object + /// Use JsonSerializer to serialise a given object. /// - /// Object Type to be serialised - /// The object to serialise - /// JsonSerializerOptions - public static Maybe Serialise(T obj, JsonSerializerOptions options) => + /// Object Type to be serialised. + /// The object to serialise. + /// JsonSerializerOptions. + public static Result Serialise(T obj, JsonSerializerOptions options) => obj switch { T x => - F.Some( - () => JsonSerializer.Serialize(x, options), - e => new M.SerialiseExceptionMsg(e) - ), + R.Try(() => JsonSerializer.Serialize(x, options)), _ => Empty }; /// - public static Maybe Serialise(T obj) => + public static Result Serialise(T obj) => Serialise(obj, Options); - - public static partial class M - { - /// Exception caught during - /// Exception object - public sealed record class DeserialiseExceptionMsg(Exception Value) : ExceptionMsg; - - /// A null or empty string cannot be deserialised - public sealed record class DeserialisingNullOrEmptyStringMsg : Msg; - - /// The object was deserialised but returned null - public sealed record class DeserialisingReturnedNullMsg : Msg; - } } diff --git a/src/Jeebs/Functions/JsonF.cs b/src/Jeebs/Functions/JsonF.cs index 3eb7382ee..edf651193 100644 --- a/src/Jeebs/Functions/JsonF.cs +++ b/src/Jeebs/Functions/JsonF.cs @@ -4,27 +4,27 @@ using System.Text.Json; using System.Text.Json.Serialization; using Jeebs.Functions.JsonConverters; -using StrongId.Json; +using Wrap.Json; namespace Jeebs.Functions; /// -/// JSON functions +/// JSON functions. /// public static partial class JsonF { /// - /// Empty JSON + /// Empty JSON string. /// public static string Empty { get; } = "\"\""; /// - /// Default JsonSerializerOptions + /// Default JsonSerializerOptions. /// public static JsonSerializerOptions Options { private get; set; } /// - /// Define default settings + /// Define default settings. /// static JsonF() { @@ -40,9 +40,6 @@ static JsonF() Options.Converters.Add(new EnumeratedJsonConverterFactory()); Options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); Options.Converters.Add(new MaybeJsonConverterFactory()); - Options.Converters.Add(new StrongIdJsonConverterFactory()); + Options.Converters.Add(new UnionJsonConverterFactory()); } - - /// Messages - public static partial class M { } } diff --git a/src/Jeebs/Functions/LogLevelF.ConvertToMicrosoftLevel.cs b/src/Jeebs/Functions/LogLevelF.ConvertToMicrosoftLevel.cs deleted file mode 100644 index a85d514de..000000000 --- a/src/Jeebs/Functions/LogLevelF.ConvertToMicrosoftLevel.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using Jeebs.Messages; -using JeebsLevel = Jeebs.Logging.LogLevel; -using MicrosoftLevel = Microsoft.Extensions.Logging.LogLevel; - -namespace Jeebs.Functions; - -public static partial class LogLevelF -{ - /// - /// Convert a to a - /// - /// - public static Maybe ConvertToMicrosoftLevel(JeebsLevel level) => - level switch - { - JeebsLevel.Verbose => - MicrosoftLevel.Trace, - - JeebsLevel.Debug => - MicrosoftLevel.Debug, - - JeebsLevel.Information => - MicrosoftLevel.Information, - - JeebsLevel.Warning => - MicrosoftLevel.Warning, - - JeebsLevel.Error => - MicrosoftLevel.Error, - - JeebsLevel.Fatal => - MicrosoftLevel.Critical, - - _ => - F.None(new M.UnknownLogLevelMsg(level)) - }; - - public static partial class M - { - /// Unknown LogLevel value - /// - public sealed record class UnknownLogLevelMsg(JeebsLevel Value) : WithValueMsg; - } -} diff --git a/src/Jeebs/Functions/LogLevelF.cs b/src/Jeebs/Functions/LogLevelF.cs deleted file mode 100644 index 0ec8faca8..000000000 --- a/src/Jeebs/Functions/LogLevelF.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Functions; - -/// -/// Log Level functions -/// -public static partial class LogLevelF -{ - /// Messages - public static partial class M { } -} diff --git a/src/Jeebs/Functions/MathsF.Combinations.cs b/src/Jeebs/Functions/MathsF.Combinations.cs index 9ed983402..65d32be8c 100644 --- a/src/Jeebs/Functions/MathsF.Combinations.cs +++ b/src/Jeebs/Functions/MathsF.Combinations.cs @@ -6,16 +6,16 @@ namespace Jeebs.Functions; public static partial class MathsF { /// - /// Calculate the number of combinations - i.e. the number of ways to choose or combine objects - /// from a total of objects
- /// Use this when order does not matter + /// Calculate the number of combinations - i.e. the number of ways to choose or combine + /// objects from a total of objects.
+ /// Use this when order does not matter. ///
/// /// and must be greater than 0, - /// and must be greater than or equal to + /// and must be greater than or equal to . /// - /// The total number of objects - /// The number of objects being selected + /// The total number of objects. + /// The number of objects being selected. public static long Combinations(long n, long r) => (n > 0 && r > 0 && n >= r) switch { diff --git a/src/Jeebs/Functions/MathsF.Factorial.cs b/src/Jeebs/Functions/MathsF.Factorial.cs index d99904e0a..3d00712d8 100644 --- a/src/Jeebs/Functions/MathsF.Factorial.cs +++ b/src/Jeebs/Functions/MathsF.Factorial.cs @@ -6,12 +6,12 @@ namespace Jeebs.Functions; public static partial class MathsF { /// - /// Calculate the factorial result of + /// Calculate the factorial result of . /// /// - /// must be greater than or equal to zero + /// must be greater than or equal to zero. /// - /// Number (greater than or equal to zero) + /// Number (greater than or equal to zero). public static long Factorial(long x) { if (x < 0) diff --git a/src/Jeebs/Functions/MathsF.Permutations.cs b/src/Jeebs/Functions/MathsF.Permutations.cs index b753cf202..e43e61b57 100644 --- a/src/Jeebs/Functions/MathsF.Permutations.cs +++ b/src/Jeebs/Functions/MathsF.Permutations.cs @@ -7,15 +7,15 @@ public static partial class MathsF { /// /// Calculate the number of permutations - i.e. the number of ways objects can be arranged - /// among places
- /// Use this when order matters + /// among placesbr/> + /// Use this when order matters. ///
/// /// and must be greater than 0, - /// and must be greater than or equal to + /// and must be greater than or equal to . /// - /// The total number of objects - /// The number of places being filled + /// The total number of objects. + /// The number of places being filled. public static long Permutations(long n, long r) => (n > 0 && r > 0 && n >= r) switch { diff --git a/src/Jeebs/Functions/MathsF.cs b/src/Jeebs/Functions/MathsF.cs index 948c62009..cb0b0dc1f 100644 --- a/src/Jeebs/Functions/MathsF.cs +++ b/src/Jeebs/Functions/MathsF.cs @@ -4,8 +4,6 @@ namespace Jeebs.Functions; /// -/// Maths Functions +/// Maths Functions. /// -public static partial class MathsF -{ -} +public static partial class MathsF { } diff --git a/src/Jeebs/Functions/PhpF.Deserialise.cs b/src/Jeebs/Functions/PhpF.Deserialise.cs index 693825578..05d9e9c3c 100644 --- a/src/Jeebs/Functions/PhpF.Deserialise.cs +++ b/src/Jeebs/Functions/PhpF.Deserialise.cs @@ -9,9 +9,9 @@ namespace Jeebs.Functions; public static partial class PhpF { /// - /// Deserialise object + /// Deserialise object. /// - /// Serialised string + /// Serialised string. public static object Deserialise(string str) { var pointer = 0; @@ -116,9 +116,9 @@ static AssocArray getArray(string str, ref int pointer) for (var i = 0; i < len; i++) { var (key, value) = (PrivateDeserialise(str, ref pointer), PrivateDeserialise(str, ref pointer)); - F.ParseInt32(key.ToString()).Switch( + M.ParseInt32(key.ToString()).Match( some: x => table.Add(x, value), - none: _ => table.Add(key, value) + none: () => table.Add(key, value) ); } diff --git a/src/Jeebs/Functions/PhpF.Serialise.cs b/src/Jeebs/Functions/PhpF.Serialise.cs index 356515a16..848647003 100644 --- a/src/Jeebs/Functions/PhpF.Serialise.cs +++ b/src/Jeebs/Functions/PhpF.Serialise.cs @@ -10,10 +10,10 @@ namespace Jeebs.Functions; public static partial class PhpF { /// - /// Serialise object + /// Serialise object. /// - /// Object type - /// Object value + /// Object type. + /// Object value. public static string Serialise(T obj) => Serialise(obj, new StringBuilder()).ToString(); diff --git a/src/Jeebs/Functions/PhpF.cs b/src/Jeebs/Functions/PhpF.cs index 021d60632..0b1c4b48f 100644 --- a/src/Jeebs/Functions/PhpF.cs +++ b/src/Jeebs/Functions/PhpF.cs @@ -7,7 +7,7 @@ namespace Jeebs.Functions; /// -/// PHP serialisation functions +/// PHP serialisation functions. /// public static partial class PhpF { diff --git a/src/Jeebs/Functions/StringF.Format.cs b/src/Jeebs/Functions/StringF.Format.cs index fbed57db6..6bf4c6098 100644 --- a/src/Jeebs/Functions/StringF.Format.cs +++ b/src/Jeebs/Functions/StringF.Format.cs @@ -9,38 +9,37 @@ namespace Jeebs.Functions; /// -/// String functions +/// String functions. /// public static partial class StringF { /// /// If is not null, use string.Format() - - /// otherwise, return + /// otherwise, return . /// - /// Object type - /// Format string - /// Object (nullable) - /// Value to return if null - public static string? Format(string formatString, T obj, string? ifNull) => + /// Object type. + /// Format string. + /// Object (nullable). + public static string Format(string formatString, T obj, string? ifNull) => obj switch { - T t => - string.Format(CultureInfo.InvariantCulture, formatString, t), + T x => + string.Format(CultureInfo.InvariantCulture, formatString, x), _ => - ifNull + ifNull ?? formatString }; /// - /// Works like string.Format() but with named as well as numbered placeholders - /// Source is Array: values will be inserted in order (regardless of placeholder values) - /// Source is Object: property names must match placeholders or they will be left in place - /// Inspired by http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables - /// (Significantly) altered to work without requiring DataBinder + /// Works like string.Format() but with named as well as numbered placeholders. + /// Source is Array: values will be inserted in order (regardless of placeholder values). + /// Source is Object: property names must match placeholders or they will be left in place. + /// Inspired by http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables. + /// (Significantly) altered to work without requiring DataBinder. /// - /// Source type - /// String to format - /// Source object to use for template values + /// Source type. + /// String to format. + /// Source object to use for template values. public static string Format(string formatString, T source) { // Return original if source is null or if it is an empty array diff --git a/src/Jeebs/Functions/ThreadF.FireAndForget.cs b/src/Jeebs/Functions/ThreadF.FireAndForget.cs index 7cb49cc04..4e9ae14c9 100644 --- a/src/Jeebs/Functions/ThreadF.FireAndForget.cs +++ b/src/Jeebs/Functions/ThreadF.FireAndForget.cs @@ -1,4 +1,4 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; @@ -7,23 +7,23 @@ namespace Jeebs.Functions; /// -/// Thread functions +/// Thread functions. /// public static class ThreadF { /// - /// Start a task and forget about it + /// Start a task and forget about it. /// - /// The task be sync or async - doesn't matter + /// The task be sync or async - doesn't matter. public static void FireAndForget(Action task) => ThreadPool.QueueUserWorkItem(_ => task()); /// - /// Start a task and forget about it + /// Start a task and forget about it. /// - /// Task state object - /// State to pass to the task - /// The task be sync or async - doesn't matter + /// Task state object. + /// State to pass to the task. + /// The task be sync or async - doesn't matter<./param> public static void FireAndForget(T state, Action task) => ThreadPool.QueueUserWorkItem(task, state, false); } diff --git a/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementing.cs b/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementing.cs index 5c7f6a404..964b31b87 100644 --- a/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementing.cs +++ b/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementing.cs @@ -10,7 +10,7 @@ namespace Jeebs.Functions; public static partial class TypeF { /// - /// Property Type + /// Property Type. public static List GetPropertyTypesImplementing() => GetPropertyTypesImplementing(typeof(T), AllTypes.Value); @@ -19,10 +19,10 @@ public static List GetPropertyTypesImplementing(Type type) => GetPropertyTypesImplementing(type, AllTypes.Value); /// - /// Get distinct property types that implement + /// Get distinct property types that implement . /// - /// Property Type - /// Type List + /// Property Type. + /// Type List. internal static List GetPropertyTypesImplementing(Type type, IEnumerable typeList) { var types = from t in typeList diff --git a/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementingGeneric.cs b/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementingGeneric.cs index e7a1e9887..face06141 100644 --- a/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementingGeneric.cs +++ b/src/Jeebs/Functions/TypeF.GetPropertyTypesImplementingGeneric.cs @@ -14,10 +14,10 @@ public static List GetPropertyTypesImplementingGeneric(Type type) => GetPropertyTypesImplementingGeneric(type, AllTypes.Value); /// - /// Get distinct property types that implement + /// Get distinct property types that implement . /// - /// Property Type - /// Type List + /// Property Type. + /// Type List. internal static List GetPropertyTypesImplementingGeneric(Type type, IEnumerable typeList) { var types = from t in typeList diff --git a/src/Jeebs/Functions/TypeF.GetTypesImplementing.cs b/src/Jeebs/Functions/TypeF.GetTypesImplementing.cs index c335cbadd..86d261ec6 100644 --- a/src/Jeebs/Functions/TypeF.GetTypesImplementing.cs +++ b/src/Jeebs/Functions/TypeF.GetTypesImplementing.cs @@ -10,7 +10,7 @@ namespace Jeebs.Functions; public static partial class TypeF { /// - /// Base Type + /// Base Type. public static List GetTypesImplementing() => GetTypesImplementing(typeof(T), AllTypes.Value); @@ -19,10 +19,10 @@ public static List GetTypesImplementing(Type type) => GetTypesImplementing(type, AllTypes.Value); /// - /// Get distinct types that implement + /// Get distinct types that implement . /// - /// Base Type - /// Type List + /// Base Type. + /// Type List. internal static List GetTypesImplementing(Type type, IEnumerable typeList) { var types = from t in typeList diff --git a/src/Jeebs/Functions/TypeF.GetTypesImplementingGeneric.cs b/src/Jeebs/Functions/TypeF.GetTypesImplementingGeneric.cs index 5bda2a510..388e2d11d 100644 --- a/src/Jeebs/Functions/TypeF.GetTypesImplementingGeneric.cs +++ b/src/Jeebs/Functions/TypeF.GetTypesImplementingGeneric.cs @@ -14,10 +14,10 @@ public static List GetTypesImplementingGeneric(Type type) => GetTypesImplementingGeneric(type, AllTypes.Value); /// - /// Get distinct types that implement a generic type + /// Get distinct types that implement a generic type . /// - /// Base Type - /// Type List + /// Base Type. + /// Type List. internal static List GetTypesImplementingGeneric(Type type, IEnumerable typeList) { var types = from t in typeList diff --git a/src/Jeebs/Functions/TypeF.cs b/src/Jeebs/Functions/TypeF.cs index cbb5dd59a..763331b9f 100644 --- a/src/Jeebs/Functions/TypeF.cs +++ b/src/Jeebs/Functions/TypeF.cs @@ -9,14 +9,13 @@ namespace Jeebs.Functions; /// -/// Type functions +/// Type functions. /// public static partial class TypeF { /// - /// Return list of all loaded assembly names - - /// excludes Microsoft.* and System.* assemblies - /// See https://dotnetcoretutorials.com/2020/07/03/getting-assemblies-is-harder-than-you-think-in-c/ + /// Return list of all loaded assembly names - excludes Microsoft.* and System.* assemblies.
+ /// See https://dotnetcoretutorials.com/2020/07/03/getting-assemblies-is-harder-than-you-think-in-c/. ///
internal static Lazy> AllAssemblyNames { get; } = new( () => @@ -48,8 +47,7 @@ public static partial class TypeF ); /// - /// Return list of all public class types in all loaded assemblies - - /// excludes Microsoft.* and System.* types + /// Return list of all public class types in all loaded assemblies - excludes Microsoft.* and System.* types. /// public static Lazy> AllTypes { get; } = new( () => diff --git a/src/Jeebs/Functions/UriF.IsHttp.cs b/src/Jeebs/Functions/UriF.IsHttp.cs index f3aafe6f7..cf35ebfae 100644 --- a/src/Jeebs/Functions/UriF.IsHttp.cs +++ b/src/Jeebs/Functions/UriF.IsHttp.cs @@ -1,4 +1,4 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; @@ -6,21 +6,19 @@ namespace Jeebs.Functions; /// -/// URI functions +/// URI functions. /// public static class UriF { /// - /// Returns true if is a valid HTTP URI + /// Returns true if is a valid HTTP URI. /// - /// Input URI - /// Set to false if you want to match HTTP URIs + /// Input URI. + /// Set to false if you want to match HTTP URIs. public static bool IsHttp(string input, bool requireHttps) => !string.IsNullOrEmpty(input) && Uri.TryCreate(input, UriKind.Absolute, out var uri) - && (uri.Scheme == Uri.UriSchemeHttps - || (!requireHttps && uri.Scheme == Uri.UriSchemeHttp) - ); + && (uri.Scheme == Uri.UriSchemeHttps || (!requireHttps && uri.Scheme == Uri.UriSchemeHttp)); /// public static bool IsHttps(string input) => diff --git a/src/Jeebs/Functions/VersionF.GetJeebsVersionAsync.cs b/src/Jeebs/Functions/VersionF.GetJeebsVersionAsync.cs index 31ed058ff..ef6e47c25 100644 --- a/src/Jeebs/Functions/VersionF.GetJeebsVersionAsync.cs +++ b/src/Jeebs/Functions/VersionF.GetJeebsVersionAsync.cs @@ -9,20 +9,19 @@ namespace Jeebs.Functions; public static partial class VersionF { /// - /// Lazy property to avoid multiple reflection calls + /// Lazy property to avoid multiple reflection calls. /// - private static LazyAsync Version { get; } = new( - () => GetVersion(typeof(VersionF).Assembly.GetManifestResourceStream("Jeebs.Version"), AssemblyVersion) - ); + private static LazyAsync Version { get; } = + new(() => GetVersion(typeof(VersionF).Assembly.GetManifestResourceStream("Jeebs.Version"), AssemblyVersion)); /// - /// Get the compiled version of the current assembly - does not include suffixes (e.g. '-beta.1') + /// Get the compiled version of the current assembly - does not include suffixes (e.g. '-beta.1'). /// internal static Version? AssemblyVersion => typeof(VersionF).Assembly.GetName().Version; /// - /// Get Jeebs Version, or return the package version if the resource cannot be found + /// Get Jeebs Version, or return the package version if the resource cannot be found. /// public static Task GetJeebsVersionAsync() => Version.Value; diff --git a/src/Jeebs/Functions/VersionF.GetVersion.cs b/src/Jeebs/Functions/VersionF.GetVersion.cs index 9c3d3f6d7..d94d19508 100644 --- a/src/Jeebs/Functions/VersionF.GetVersion.cs +++ b/src/Jeebs/Functions/VersionF.GetVersion.cs @@ -10,10 +10,10 @@ namespace Jeebs.Functions; public static partial class VersionF { /// - /// Get version from the specified stream, Version property, or default (0.0.0.0) + /// Get version from the specified stream, Version property, or default (0.0.0.0). /// - /// Stream containing version file - /// Version object + /// Stream containing version file. + /// Version object. internal static async Task GetVersion(Stream? stream, Version? version) { // Attempt to read from stream @@ -41,9 +41,9 @@ internal static async Task GetVersion(Stream? stream, Version? version) } /// - /// Return version formatted as x.x.x.x + /// Return version formatted as x.x.x.x. /// - /// Version + /// Version. internal static string GetVersionString(Version version) => $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"; } diff --git a/src/Jeebs/Functions/VersionF.cs b/src/Jeebs/Functions/VersionF.cs index 0b0f9f60e..704906178 100644 --- a/src/Jeebs/Functions/VersionF.cs +++ b/src/Jeebs/Functions/VersionF.cs @@ -4,8 +4,6 @@ namespace Jeebs.Functions; /// -/// Version functions +/// Version functions. /// -public static partial class VersionF -{ -} +public static partial class VersionF { } From fb1d143472f9c9237fd09b4a42210e014cb6b7d8 Mon Sep 17 00:00:00 2001 From: bfren Date: Tue, 26 Mar 2024 09:42:02 +0000 Subject: [PATCH 030/202] Switching to use Wrap instead of Maybe --- src/Directory.Build.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9ece383a1..9fb180416 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -10,9 +10,9 @@ - - - + + + From fabeb977f8ffca1c6e8418083cb25c6f09566380 Mon Sep 17 00:00:00 2001 From: bfren Date: Wed, 27 Mar 2024 11:03:20 +0000 Subject: [PATCH 031/202] Moving MaybeJsonConverter to Wrap project --- Directory.Packages.props | 2 + .../JsonConverters/MaybeJsonConverter.cs | 59 ------------------- .../MaybeJsonConverterFactory.cs | 44 -------------- src/Jeebs/Functions/JsonF.cs | 2 +- src/Jeebs/Jeebs.csproj | 1 + 5 files changed, 4 insertions(+), 104 deletions(-) delete mode 100644 src/Jeebs/Functions/JsonConverters/MaybeJsonConverter.cs delete mode 100644 src/Jeebs/Functions/JsonConverters/MaybeJsonConverterFactory.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index fc14237e5..bbc8b4edc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -56,6 +56,8 @@ + + diff --git a/src/Jeebs/Functions/JsonConverters/MaybeJsonConverter.cs b/src/Jeebs/Functions/JsonConverters/MaybeJsonConverter.cs deleted file mode 100644 index 82808a582..000000000 --- a/src/Jeebs/Functions/JsonConverters/MaybeJsonConverter.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using Jeebs.Messages; - -namespace Jeebs.Functions.JsonConverters; - -/// -/// JSON converter -/// -/// Maybe value type -internal sealed class MaybeJsonConverter : JsonConverter> -{ - /// - /// Read value and return as or - /// - /// Utf8JsonReader - /// Maybe of type - /// JsonSerializerOptions - public override Maybe? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => - JsonSerializer.Deserialize(ref reader, options) switch - { - T value => - value, - - _ => - F.None() // should never get here - }; - - /// - /// If the Maybe is write the value, otherwise write a null value - /// - /// Utf8JsonWriter - /// Maybe value - /// JsonSerializerOptions - public override void Write(Utf8JsonWriter writer, Maybe value, JsonSerializerOptions options) - { - if (value.IsSome(out var obj)) - { - JsonSerializer.Serialize(writer, obj, options); - } - else - { - writer.WriteStringValue(string.Empty); - } - } -} - -/// -/// Wrapper for messages because it has a generic constraint -/// -internal static class M -{ - /// Deserialisation returned a null value - public sealed record class DeserialisingReturnedNullMsg() : Msg; -} diff --git a/src/Jeebs/Functions/JsonConverters/MaybeJsonConverterFactory.cs b/src/Jeebs/Functions/JsonConverters/MaybeJsonConverterFactory.cs deleted file mode 100644 index fd704a794..000000000 --- a/src/Jeebs/Functions/JsonConverters/MaybeJsonConverterFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Jeebs.Functions.JsonConverters; - -/// -/// JSON converter factory -/// -internal sealed class MaybeJsonConverterFactory : JsonConverterFactory -{ - /// - /// Returns true if inherits from - /// - /// Type to convert - public override bool CanConvert(Type typeToConvert) => - typeToConvert.Implements(typeof(Maybe<>)); - - /// - /// Creates JsonConverter for - /// - /// Maybe type - /// JsonSerializerOptions - /// - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { - // Get converter type - var wrappedType = typeToConvert.GetGenericArguments()[0]; - var converterType = typeof(MaybeJsonConverter<>).MakeGenericType(wrappedType); - - // Create converter - return Activator.CreateInstance(converterType) switch - { - JsonConverter x => - x, - - _ => - throw new JsonException($"Unable to create {converterType} for type {typeToConvert}.") - }; - } -} diff --git a/src/Jeebs/Functions/JsonF.cs b/src/Jeebs/Functions/JsonF.cs index edf651193..99d94049a 100644 --- a/src/Jeebs/Functions/JsonF.cs +++ b/src/Jeebs/Functions/JsonF.cs @@ -24,7 +24,7 @@ public static partial class JsonF public static JsonSerializerOptions Options { private get; set; } /// - /// Define default settings. + /// Define default settings and add standard converters. /// static JsonF() { diff --git a/src/Jeebs/Jeebs.csproj b/src/Jeebs/Jeebs.csproj index 98af0c01f..fc977123c 100644 --- a/src/Jeebs/Jeebs.csproj +++ b/src/Jeebs/Jeebs.csproj @@ -9,6 +9,7 @@ + From f88cbd8101733182ae04f73126e4f0802e71b205 Mon Sep 17 00:00:00 2001 From: bfren Date: Wed, 27 Mar 2024 13:38:07 +0000 Subject: [PATCH 032/202] Making comments consistent, using new array initialisers, switching to use Wrap class --- src/Jeebs/ArrayExtensions.cs | 2 +- .../Collections/Defaults/PagingValues.cs | 6 +- src/Jeebs/Collections/EnumerableExtensions.cs | 54 ++--- src/Jeebs/Collections/EnumeratedList.cs | 23 +-- src/Jeebs/Collections/IImmutableList.cs | 42 ++-- src/Jeebs/Collections/IPagedList.cs | 6 +- src/Jeebs/Collections/IPagingValues.cs | 24 +-- src/Jeebs/Collections/ImmutableList.cs | 90 ++------- src/Jeebs/Collections/ListExtensions.cs | 98 +++------- src/Jeebs/Collections/PagedList.cs | 8 +- src/Jeebs/Collections/PagedListExtensions.cs | 11 +- src/Jeebs/Collections/PagingValues.cs | 20 +- src/Jeebs/Config/App/AppConfig.cs | 12 +- src/Jeebs/Config/Azure/AzureConfig.cs | 8 +- .../DataProtection/DataProtectionConfig.cs | 22 ++- .../Config/Azure/KeyVault/KeyVaultConfig.cs | 22 ++- src/Jeebs/Config/ConfigurationExtensions.cs | 30 +-- src/Jeebs/Config/Db/DbConfig.cs | 52 +++-- src/Jeebs/Config/Db/DbConnectionConfig.cs | 8 +- .../DefaultDbConnectionUndefinedException.cs | 30 --- .../Db/NamedDbConnectionNotFoundException.cs | 37 ---- .../Config/Db/NoDbConnectionsException.cs | 30 --- src/Jeebs/Config/JeebsConfig.cs | 23 +-- src/Jeebs/Config/Logging/LoggingConfig.cs | 12 +- .../Config/Logging/LoggingProviderConfig.cs | 8 +- .../Config/Services/Console/ConsoleConfig.cs | 6 +- src/Jeebs/Config/Services/IServiceConfig.cs | 6 +- .../Config/Services/IWebhookServiceConfig.cs | 6 +- .../InvalidServiceConfigurationException.cs | 44 ----- .../InvalidServiceDefinitionException.cs | 37 ---- src/Jeebs/Config/Services/Seq/SeqConfig.cs | 6 +- src/Jeebs/Config/Services/ServicesConfig.cs | 133 ++++++------- .../Config/Services/Slack/SlackConfig.cs | 4 +- .../Services/UnknownServiceException.cs | 44 ----- .../Services/UnsupportedServiceException.cs | 37 ---- src/Jeebs/Config/Web/Auth/AuthConfig.cs | 14 +- .../Web/Auth/AuthNotEnabledException.cs | 30 --- src/Jeebs/Config/Web/Auth/AuthScheme.cs | 6 +- .../Jwt/InvalidJwtConfigurationException.cs | 30 --- src/Jeebs/Config/Web/Auth/Jwt/JwtConfig.cs | 16 +- .../Auth/UnsupportedAuthSchemeException.cs | 37 ---- .../Web/Redirections/RedirectionsConfig.cs | 4 +- .../Web/Verification/VerificationConfig.cs | 8 +- src/Jeebs/Config/Web/WebConfig.cs | 10 +- src/Jeebs/Config/WordPress/WpConfig.cs | 16 +- src/Jeebs/Constants/BibleBooks.cs | 185 +++++++++--------- src/Jeebs/Constants/UnPluralisables.cs | 11 +- src/Jeebs/DateTimeExtensions.cs | 2 +- .../StringExtensions.ConvertCurlyQuotes.cs | 57 +++--- ...StringExtensions.ConvertInnerHtmlQuotes.cs | 5 +- .../Extensions/StringExtensions.EndWith.cs | 14 +- .../StringExtensions.EscapeSingleQuotes.cs | 5 +- .../Extensions/StringExtensions.GetAcronym.cs | 5 +- .../StringExtensions.GetMimeFromExtension.cs | 5 +- .../Extensions/StringExtensions.HtmlDecode.cs | 5 +- .../Extensions/StringExtensions.HtmlEncode.cs | 5 +- .../StringExtensions.NoLongerThan.cs | 29 +-- .../Extensions/StringExtensions.Normalise.cs | 21 +- .../StringExtensions.NullIfEmpty.cs | 14 -- .../Extensions/StringExtensions.Pluralise.cs | 19 +- .../Extensions/StringExtensions.ReplaceAll.cs | 9 +- .../StringExtensions.ReplaceHtmlTags.cs | 27 +-- .../StringExtensions.ReplaceNonLetter.cs | 25 +++ .../StringExtensions.ReplaceNonNumerical.cs | 30 +-- .../StringExtensions.ReplaceNonWord.cs | 30 +-- .../StringExtensions.Singularise.cs | 11 +- .../StringExtensions.SplitByCapitals.cs | 11 +- .../Extensions/StringExtensions.StartWith.cs | 16 +- .../Extensions/StringExtensions.ToASCII.cs | 9 +- .../StringExtensions.ToCamelCase.cs | 21 ++ .../StringExtensions.ToKebabCase.cs | 21 ++ .../StringExtensions.ToLowerFirst.cs | 13 +- .../StringExtensions.ToPascalCase.cs | 21 ++ .../StringExtensions.ToSentenceCase.cs | 9 +- .../StringExtensions.ToSnakeCase.cs | 21 ++ .../StringExtensions.ToTitleCase.cs | 5 +- .../StringExtensions.ToUpperFirst.cs | 13 +- .../Extensions/StringExtensions.TrimEnd.cs | 7 +- .../Extensions/StringExtensions.TrimStart.cs | 25 +++ src/Jeebs/Extensions/StringExtensions.cs | 29 +-- .../JsonConverters/DateTimeJsonConverter.cs | 4 +- src/Jeebs/Functions/ListF.cs | 64 ++++++ src/Jeebs/LogLevelExtensions.cs | 3 + .../Reflection/LinqExpressionExtensions.cs | 21 +- src/Jeebs/Reflection/ObjectExtensions.cs | 54 ++--- .../Reflection/PropertyInfoExtensions.cs | 6 +- src/Jeebs/ResultExtensions.cs | 2 +- src/Jeebs/TypeExtensions.cs | 2 +- 88 files changed, 892 insertions(+), 1171 deletions(-) delete mode 100644 src/Jeebs/Config/Db/DefaultDbConnectionUndefinedException.cs delete mode 100644 src/Jeebs/Config/Db/NamedDbConnectionNotFoundException.cs delete mode 100644 src/Jeebs/Config/Db/NoDbConnectionsException.cs delete mode 100644 src/Jeebs/Config/Services/InvalidServiceConfigurationException.cs delete mode 100644 src/Jeebs/Config/Services/InvalidServiceDefinitionException.cs delete mode 100644 src/Jeebs/Config/Services/UnknownServiceException.cs delete mode 100644 src/Jeebs/Config/Services/UnsupportedServiceException.cs delete mode 100644 src/Jeebs/Config/Web/Auth/AuthNotEnabledException.cs delete mode 100644 src/Jeebs/Config/Web/Auth/Jwt/InvalidJwtConfigurationException.cs delete mode 100644 src/Jeebs/Config/Web/Auth/UnsupportedAuthSchemeException.cs delete mode 100644 src/Jeebs/Extensions/StringExtensions.NullIfEmpty.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.ReplaceNonLetter.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.ToCamelCase.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.ToKebabCase.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.ToPascalCase.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.ToSnakeCase.cs create mode 100644 src/Jeebs/Extensions/StringExtensions.TrimStart.cs create mode 100644 src/Jeebs/Functions/ListF.cs diff --git a/src/Jeebs/ArrayExtensions.cs b/src/Jeebs/ArrayExtensions.cs index bac323398..42aac66ad 100644 --- a/src/Jeebs/ArrayExtensions.cs +++ b/src/Jeebs/ArrayExtensions.cs @@ -4,7 +4,7 @@ namespace Jeebs; /// -/// Array Extensions +/// Extension methods for objects. /// public static class ArrayExtensions { diff --git a/src/Jeebs/Collections/Defaults/PagingValues.cs b/src/Jeebs/Collections/Defaults/PagingValues.cs index a8f81c76b..3e288c100 100644 --- a/src/Jeebs/Collections/Defaults/PagingValues.cs +++ b/src/Jeebs/Collections/Defaults/PagingValues.cs @@ -4,17 +4,17 @@ namespace Jeebs.Collections.Defaults; /// -/// Defaults for Paging Values +/// Defaults for Paging Values. /// public static class PagingValues { /// - /// The number of items to display on each page of results + /// The number of items to display on each page of results. /// public static readonly ulong ItemsPer = 10; /// - /// The number of pages per group of page numbers + /// The number of pages per group of page numbers. /// public static readonly ulong PagesPer = 10; } diff --git a/src/Jeebs/Collections/EnumerableExtensions.cs b/src/Jeebs/Collections/EnumerableExtensions.cs index 45ce6b188..b5923bf75 100644 --- a/src/Jeebs/Collections/EnumerableExtensions.cs +++ b/src/Jeebs/Collections/EnumerableExtensions.cs @@ -9,17 +9,18 @@ namespace Jeebs.Collections; /// -/// IEnumerable Extensions - Filter +/// Extension methods for objects. /// public static class EnumerableExtensions { /// - /// Filter out null items (and empty / whitespace strings) from a list + /// Filter out null items (and empty / whitespace strings) from a list. /// - /// Input value type - /// Output value type - /// List - /// Mapping function + /// Input value type. + /// Output value type. + /// List. + /// Mapping function. + /// Original list with null and empty items removed. public static IEnumerable Filter(this IEnumerable @this, Func map) where TReturn : class { @@ -43,12 +44,13 @@ public static IEnumerable Filter(this IEnumerable @this, } /// - /// Filter out null items from a list + /// Filter out null items from a list. /// - /// Input value type - /// Output value type - /// List - /// Mapping function + /// Input value type. + /// Output value type. + /// List. + /// Mapping function. + /// Original list with null items removed. public static IEnumerable Filter(this IEnumerable @this, Func map) where TReturn : struct { @@ -62,30 +64,34 @@ public static IEnumerable Filter(this IEnumerable @this, } /// - /// Convert a collection to an immutable list + /// Convert a collection to an immutable list. /// - /// Item type - /// Collection + /// Item type. + /// Collection. + /// Immutable List public static IImmutableList ToImmutableList(this IEnumerable @this) => new ImmutableList(@this); /// - /// Convert a collection to a paged list using and + /// Convert a collection to a paged list using and , + /// using default paging values. /// - /// Item type - /// Collection - /// Current page + /// Item type. + /// Collection. + /// Current page. + /// Paged List containing items on page . public static IPagedList ToPagedList(this IEnumerable @this, ulong page) => ToPagedList(@this, page, D.ItemsPer, D.PagesPer); /// - /// Convert a collection to a paged list + /// Convert a collection to a paged list. /// - /// Item type - /// Collection - /// Current page - /// Items per page - /// Pages per screen + /// Item type. + /// Collection. + /// Current page. + /// Items per page. + /// Pages per screen. + /// Paged List containing items on page . public static IPagedList ToPagedList( this IEnumerable @this, ulong page, diff --git a/src/Jeebs/Collections/EnumeratedList.cs b/src/Jeebs/Collections/EnumeratedList.cs index 09965ff9b..f76e47332 100644 --- a/src/Jeebs/Collections/EnumeratedList.cs +++ b/src/Jeebs/Collections/EnumeratedList.cs @@ -11,34 +11,34 @@ namespace Jeebs.Collections; public static class EnumeratedList { /// - /// Deserialise list from JSON + /// Deserialise list from JSON. /// - /// Enumerated value type - /// JSON serialised list + /// Enumerated value type. + /// JSON serialised list. public static EnumeratedList Deserialise(string json) where T : Enumerated { - var strings = JsonF.Deserialise>(json).Unwrap(() => new List()); + var strings = JsonF.Deserialise>(json).Unwrap(_ => []); return new EnumeratedList(strings); } } /// -/// Enumerated List +/// Enumerated List. /// -/// Enumerated value type +/// Enumerated value type. public sealed class EnumeratedList : List where T : Enumerated { /// - /// Empty constructor + /// Empty constructor. /// public EnumeratedList() { } /// - /// Construct object from list of string values + /// Construct object from list of string values. /// - /// List of values + /// List of values. public EnumeratedList(List list) { if (list is null) @@ -56,9 +56,10 @@ public EnumeratedList(List list) } /// - /// Serialise list as JSON + /// Serialise list as JSON. /// - public Maybe Serialise() + /// JSON-serialised string. + public Result Serialise() { var list = new List(); ForEach(e => list.Add(e)); diff --git a/src/Jeebs/Collections/IImmutableList.cs b/src/Jeebs/Collections/IImmutableList.cs index 9aa20a6ed..aa6bcc810 100644 --- a/src/Jeebs/Collections/IImmutableList.cs +++ b/src/Jeebs/Collections/IImmutableList.cs @@ -7,71 +7,71 @@ namespace Jeebs.Collections; /// -/// Immutable List +/// Immutable List. /// -/// List Item type +/// List Item type. public interface IImmutableList : IEnumerable { /// - /// Get the item at the specified index + /// Get the item at the specified index. /// - /// Item index + /// Item index. Maybe this[int index] { get; } /// - /// Return the number of items in this + /// Return the number of items in this . /// int Count { get; } /// - /// Return the as an enumerable + /// Return the as an enumerable. /// IEnumerable AsEnumerable(); /// - /// Return the as an array + /// Return the as an array. /// T[] ToArray(); /// - /// Return the as an ordinary list + /// Return the as an ordinary list. /// List ToList(); /// - /// Create a new with the specified item added to the end + /// Create a new with the specified item added to the end. /// - /// Item to add + /// Item to add. IImmutableList WithItem(T itemToAdd); /// - /// Create a new without the specified item + /// Create a new without the specified item. /// - /// Item to remove + /// Item to remove. IImmutableList WithoutItem(T itemToRemove); /// - /// Create a new with the specified items added to the end + /// Create a new with the specified items added to the end. /// - /// Collection of items to add + /// Collection of items to add. IImmutableList WithRange(params T[] itemsToAdd); /// - /// Create a new with the specified items removed + /// Create a new with the specified items removed. /// - /// Collection of items to remove + /// Collection of items to remove. IImmutableList WithoutRange(params T[] itemsToRemove); /// - /// Create a new with one item replaced by another + /// Create a new with one item replaced by another. /// - /// Item to remove - /// Item to add + /// Item to remove. + /// Item to add. IImmutableList Replace(T remove, T add); /// - /// Filter the list based on + /// Filter the list based on . /// - /// Item predicate - if true will be included + /// Item predicate - if true will be included. IImmutableList Filter(Func predicate); } diff --git a/src/Jeebs/Collections/IPagedList.cs b/src/Jeebs/Collections/IPagedList.cs index 6f1fab911..744021c9d 100644 --- a/src/Jeebs/Collections/IPagedList.cs +++ b/src/Jeebs/Collections/IPagedList.cs @@ -4,13 +4,13 @@ namespace Jeebs.Collections; /// -/// List that supports paging operations +/// List that supports paging operations. /// -/// Type of objects in the list +/// Type of objects in the list. public interface IPagedList : IImmutableList { /// - /// IPagingValues used to create this list + /// IPagingValues used to create this list. /// IPagingValues Values { get; } } diff --git a/src/Jeebs/Collections/IPagingValues.cs b/src/Jeebs/Collections/IPagingValues.cs index 2ca5e2592..ef7b6c4ee 100644 --- a/src/Jeebs/Collections/IPagingValues.cs +++ b/src/Jeebs/Collections/IPagingValues.cs @@ -4,62 +4,62 @@ namespace Jeebs.Collections; /// -/// Paging Values interface +/// Paging Values interface. /// public interface IPagingValues { /// - /// The total number of items that match the search + /// The total number of items that match the search. /// ulong Items { get; } /// - /// The number of items to display on each page of results + /// The number of items to display on each page of results. /// ulong ItemsPer { get; } /// - /// The index of the first item being displayed + /// The index of the first item being displayed. /// ulong FirstItem { get; } /// - /// The index + 1 of the last item being displayed + /// The index + 1 of the last item being displayed. /// ulong LastItem { get; } /// - /// The page number to display + /// The page number to display. /// ulong Page { get; } /// - /// The number of pages needed to display all the items + /// The number of pages needed to display all the items. /// ulong Pages { get; } /// - /// The number of pages per group of page numbers + /// The number of pages per group of page numbers. /// ulong PagesPer { get; } /// - /// The first page to display + /// The first page to display. /// ulong LowerPage { get; } /// - /// The last page to display + /// The last page to display. /// ulong UpperPage { get; } /// - /// The number of items to Skip() in a Linq query + /// The number of items to Skip() in a Linq query. /// int Skip { get; } /// - /// The number of items to Take() in a Linq query + /// The number of items to Take() in a Linq query. /// int Take { get; } } diff --git a/src/Jeebs/Collections/ImmutableList.cs b/src/Jeebs/Collections/ImmutableList.cs index b5924630e..3e23b6100 100644 --- a/src/Jeebs/Collections/ImmutableList.cs +++ b/src/Jeebs/Collections/ImmutableList.cs @@ -5,71 +5,14 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Jeebs.Functions; -using Sys = System.Collections.Immutable; +using SCI = System.Collections.Immutable; namespace Jeebs.Collections; -/// -/// Alternative methods for creating an -/// -public static class ImmutableList -{ - /// - /// Create an empty - /// - /// List Item type - public static ImmutableList Empty() => - new(); - - /// - /// Create a new with the specified - /// - /// List Item type - /// Collection of items to add - public static ImmutableList Create(IEnumerable items) => - new(items); - - /// - /// Create a new with the specified - /// - /// List Item type - /// Items to add - public static ImmutableList Create(params T[]? args) => - args switch - { - T[] => - new(args), - - _ => - new() - }; - - /// - /// Deserialise a JSON list into an ImmutableList - /// - /// List Item type - /// JSON list - public static ImmutableList Deserialise(string json) => - JsonF.Deserialise>(json) - .Switch( - some: x => Create(items: x), - none: _ => new() - ); - - /// - /// Merge multiple objects into one - /// - /// List Item type - /// Lists to merge - public static ImmutableList Merge(params IImmutableList[] lists) => - new(lists.SelectMany(x => x)); -} - /// public record class ImmutableList : IImmutableList, IEquatable> { - internal Sys.ImmutableList List { get; init; } + internal SCI.ImmutableList List { get; init; } /// public Maybe this[int index] => @@ -80,21 +23,17 @@ public record class ImmutableList : IImmutableList, IEquatable - /// Create a new, empty + /// Create a new, empty . /// - public ImmutableList() : - this(Sys.ImmutableList.Empty) - { } + public ImmutableList() : this(SCI.ImmutableList.Empty) { } /// - /// Create a new with the specified + /// Create a new with the specified . /// - /// Collection of items to add - public ImmutableList(IEnumerable collection) : - this(Sys.ImmutableList.Empty.AddRange(collection)) - { } + /// Collection of items to add. + public ImmutableList(IEnumerable collection) : this(SCI.ImmutableList.Empty.AddRange(collection)) { } - internal ImmutableList(Sys.ImmutableList list) => + internal ImmutableList(SCI.ImmutableList list) => List = list; /// @@ -103,11 +42,11 @@ public IEnumerable AsEnumerable() => /// public T[] ToArray() => - List.ToArray(); + [.. List]; /// public List ToList() => - List.ToList(); + [.. List]; /// public IImmutableList WithItem(T itemToAdd) => @@ -141,9 +80,10 @@ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// - /// Compare sequences + /// Compare sequences. /// - /// Another list to compare with this one + /// Another list to compare with this one. + /// True if and are equal. public virtual bool Equals(ImmutableList? other) => other switch { @@ -154,9 +94,7 @@ public virtual bool Equals(ImmutableList? other) => false }; - /// - /// Return list hash code - /// + /// public override int GetHashCode() => List.GetHashCode(); } diff --git a/src/Jeebs/Collections/ListExtensions.cs b/src/Jeebs/Collections/ListExtensions.cs index 0c6a9ca93..dc34c65e2 100644 --- a/src/Jeebs/Collections/ListExtensions.cs +++ b/src/Jeebs/Collections/ListExtensions.cs @@ -3,74 +3,58 @@ using System; using System.Collections.Generic; -using Jeebs.Messages; namespace Jeebs.Collections; /// -/// Extensions +/// Extension methods for objects. /// public static class ListExtensions { /// - /// Return the items either side of - or + /// Return the items either side of - or . /// /// /// NB: if there are multiple items matching , the first will be used /// (this is how works) /// - /// Item type - /// List of items - /// Item to match + /// Item type. + /// List of items. + /// Item to match. + /// The items in the list either side of . public static (Maybe prev, Maybe next) GetEitherSide(this List @this, T item) { - static (Maybe, Maybe) invalid(Msg reason) => - (F.None(reason), F.None(reason)); - // There are no items - if (@this.Count == 0) - { - return invalid(new M.ListIsEmptyMsg()); - } - // There is only one item - if (@this.Count == 1) - { - return invalid(new M.ListContainsSingleItemMsg()); - } - // The item is not in the list - if (!@this.Contains(item)) + if (@this.Count == 0 || @this.Count == 1 || !@this.Contains(item)) { - return invalid(new M.ListDoesNotContainItemMsg(item)); + return (M.None, M.None); } - // Get the index of the item - var index = @this.IndexOf(item); - - // If it is the first item, Previous should be None - if (index == 0) - { - return (F.None(), @this[1]); - } - // If it is the last item, Next should be None - else if (index == @this.Count - 1) + return @this.IndexOf(item) switch { - return (@this[index - 1], F.None()); - } - // Return the items either side of the item - else - { - return (@this[index - 1], @this[index + 1]); - } + // If it is the first item, Previous should be None + 0 => + (M.None, @this[1]), + + // If it is the last item, Next should be None + { } x when x == @this.Count - 1 => + (@this[^1], M.None), + + // Return the items either side of the item + { } x => + (@this[x - 1], @this[x + 1]) + }; } /// - /// Get a slice of values from a list + /// Get a slice of values from a list. /// - /// List item type - /// List - /// Range of slice to return (exclusive of end element) + /// List item type. + /// List. + /// Range of slice to return (exclusive of end element). + /// Slice of values defined by . public static List GetSlice(this List @this, Range range) { var (start, length) = range.GetOffsetAndLength(@this.Count); @@ -78,11 +62,12 @@ public static List GetSlice(this List @this, Range range) } /// - /// Sort a list of Bible books, according to their place in Scripture + /// Sort a list of items containing a Bible Book property, according to their place in Scripture. /// - /// Object Type - /// The list of Bible Books - /// Function to return name of Bible Book + /// List item type. + /// The list of objects to sort by Bible Book. + /// Bible Book selector. + /// List of items sorted by Bible Book. public static void SortBibleBooks(this List @this, Func getName) { // If empty list, do nothing @@ -102,25 +87,4 @@ public static void SortBibleBooks(this List @this, Func getName // Sort list @this.Sort(comp); } - - /// Messages - public static class M - { - /// List is empty - public sealed record class ListIsEmptyMsg : Msg; - - /// List contains only one item - public sealed record class ListContainsSingleItemMsg : Msg; - - /// List does not contain the specified item - /// Value type - /// Item Value - public sealed record class ListDoesNotContainItemMsg(T Value) : WithValueMsg; - - /// The specified item is the first in the list (so there is no previous item) - public sealed record class ItemIsFirstItemMsg : Msg; - - /// The specified item is the last in the list (so there is no next item) - public sealed record class ItemIsLastItemMsg : Msg; - } } diff --git a/src/Jeebs/Collections/PagedList.cs b/src/Jeebs/Collections/PagedList.cs index 38b5556b5..bfed79ded 100644 --- a/src/Jeebs/Collections/PagedList.cs +++ b/src/Jeebs/Collections/PagedList.cs @@ -12,16 +12,16 @@ public sealed record class PagedList : ImmutableList, IPagedList public IPagingValues Values { get; init; } /// - /// Create an empty PagedList + /// Create an empty PagedList. /// public PagedList() => Values = new PagingValues(); /// - /// Create PagedList from a collection of items + /// Create PagedList from a collection of items. /// - /// PagingValues - /// Collection + /// PagingValues. + /// Collection. public PagedList(IPagingValues values, IEnumerable collection) : base(collection) => Values = values; } diff --git a/src/Jeebs/Collections/PagedListExtensions.cs b/src/Jeebs/Collections/PagedListExtensions.cs index 048dc1e9d..a8eecd672 100644 --- a/src/Jeebs/Collections/PagedListExtensions.cs +++ b/src/Jeebs/Collections/PagedListExtensions.cs @@ -4,16 +4,17 @@ namespace Jeebs.Collections; /// -/// Extensions +/// Extension methods for objects. /// public static class PagedListExtensions { /// - /// Modify 'pages per' in pagination (the other paging values cannot be changed) + /// Modify 'pages per' in pagination (the other paging values cannot be changed). /// - /// List item type - /// IPagedList - /// The new number of pages per pagination + /// List item type. + /// IPagedList. + /// The new number of pages per pagination. + /// New with updated pages per screen value. public static IPagedList WithPagesPer(this IPagedList @this, ulong pagesPer) => new PagedList(new PagingValues(@this.Values.Items, @this.Values.Page, @this.Values.ItemsPer, pagesPer), @this); } diff --git a/src/Jeebs/Collections/PagingValues.cs b/src/Jeebs/Collections/PagingValues.cs index e7bb19e51..5662b524b 100644 --- a/src/Jeebs/Collections/PagingValues.cs +++ b/src/Jeebs/Collections/PagingValues.cs @@ -48,20 +48,22 @@ public sealed record class PagingValues : IPagingValues public PagingValues() { } /// - /// Set and calculate values using and + /// Set and calculate values using and . /// - /// Total number of items - /// Current page + /// Total number of items. + /// Current page. public PagingValues(ulong items, ulong page) : this(items, page, D.ItemsPer, D.PagesPer) { } /// - /// Set and calculate values - /// If is 0, paging will not be used + /// Set and calculate values. /// - /// Total number of items - /// Current page - /// Number of items per page - /// Number of page numbers before using next / previous + /// + /// If is 0, paging will not be used. + /// + /// Total number of items. + /// Current page. + /// Number of items per page. + /// Number of page numbers before using next / previous. public PagingValues(ulong items, ulong page, ulong itemsPer, ulong pagesPer) { // If itemsPerPage is zero, use totalItems instead (i.e. no paging) diff --git a/src/Jeebs/Config/App/AppConfig.cs b/src/Jeebs/Config/App/AppConfig.cs index b409ba6d6..52282fd09 100644 --- a/src/Jeebs/Config/App/AppConfig.cs +++ b/src/Jeebs/Config/App/AppConfig.cs @@ -8,34 +8,34 @@ namespace Jeebs.Config.App; /// -/// Jeebs Application Configuraiton +/// Jeebs Application Configuration. /// public sealed record class AppConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = JeebsConfig.Key + ":app"; /// - /// Application Name + /// Application Name. /// public string Name { get; init; } = string.Empty; /// - /// The Application Suite property to add to log messages + /// The Application Suite property to add to log messages. /// public string? Suite { get; init; } /// /// The full name - if is set, returns /, - /// otherwise simply + /// otherwise simply . /// public string FullName => StringF.Format("{0}/", Suite, string.Empty) + Name; /// - /// Application Version + /// Application Version. /// public Version Version { get; init; } = new Version(0, 1, 0, 0); diff --git a/src/Jeebs/Config/Azure/AzureConfig.cs b/src/Jeebs/Config/Azure/AzureConfig.cs index e6bc17fba..542701090 100644 --- a/src/Jeebs/Config/Azure/AzureConfig.cs +++ b/src/Jeebs/Config/Azure/AzureConfig.cs @@ -6,22 +6,22 @@ namespace Jeebs.Config.Azure; /// -/// Azure Configuration +/// Azure Configuration. /// public sealed record class AzureConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = JeebsConfig.Key + ":azure"; /// - /// DataProtectionConfig + /// DataProtectionConfig. /// public DataProtection.DataProtectionConfig Verification { get; init; } = new(); /// - /// KeyVaultConfig + /// KeyVaultConfig. /// public KeyVault.KeyVaultConfig Redirections { get; init; } = new(); diff --git a/src/Jeebs/Config/Azure/DataProtection/DataProtectionConfig.cs b/src/Jeebs/Config/Azure/DataProtection/DataProtectionConfig.cs index fe07f6865..f679f1a1d 100644 --- a/src/Jeebs/Config/Azure/DataProtection/DataProtectionConfig.cs +++ b/src/Jeebs/Config/Azure/DataProtection/DataProtectionConfig.cs @@ -7,38 +7,42 @@ namespace Jeebs.Config.Azure.DataProtection; /// -/// Azure Key Vault Configuration -/// These values should only ever be set in jeebsconfig-secrets.json to avoid them being checked into version control +/// Azure Key Vault Configuration. /// +/// +/// These values should only ever be set in jeebsconfig-secrets.json to avoid them being checked into version control +/// public sealed record class DataProtectionConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = AzureConfig.Key + ":dataProtection"; /// - /// Azure storage access key connection string + /// Azure storage access key connection string. /// public string StorageAccessKeyConnectionString { get; init; } = string.Empty; /// - /// Blob Container name + /// Blob Container name. /// public string ContainerName { get; init; } = string.Empty; /// - /// Blob name (e.g. keys.xml) + /// Blob name (e.g. keys.xml). /// public string BlobName { get; init; } = "keys.xml"; /// - /// URI to encryption key in Azure Key Vault + /// URI to encryption key in Azure Key Vault. /// public string KeyUri { get; init; } = string.Empty; /// - /// Only returns True if , , , and are all not null or empty + /// Only returns True if , + /// , , + /// and are all not null or empty. /// public bool IsValid => !string.IsNullOrWhiteSpace(StorageAccessKeyConnectionString) @@ -51,7 +55,7 @@ public sealed record class DataProtectionConfig : IOptions this; /// - /// Get Azure Key URI + /// Get Azure Key URI. /// public Uri GetUri() => new(KeyUri); diff --git a/src/Jeebs/Config/Azure/KeyVault/KeyVaultConfig.cs b/src/Jeebs/Config/Azure/KeyVault/KeyVaultConfig.cs index 094c60296..915f3dc4e 100644 --- a/src/Jeebs/Config/Azure/KeyVault/KeyVaultConfig.cs +++ b/src/Jeebs/Config/Azure/KeyVault/KeyVaultConfig.cs @@ -7,38 +7,41 @@ namespace Jeebs.Config.Azure.KeyVault; /// -/// Azure Key Vault Configuration -/// These values should only ever be set in jeebsconfig-secrets.json to avoid them being checked into version control +/// Azure Key Vault Configuration. /// +/// +/// These values should only ever be set in jeebsconfig-secrets.json to avoid them being checked into version control +/// public sealed record class KeyVaultConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = AzureConfig.Key + ":keyVault"; /// - /// Azure Key Vault Name + /// Azure Key Vault Name. /// public string Name { get; init; } = string.Empty; /// - /// Tenant (or Directory) ID + /// Tenant (or Directory) ID. /// public string TenantId { get; init; } = string.Empty; /// - /// Client ID + /// Client ID. /// public string ClientId { get; init; } = string.Empty; /// - /// Client Secret + /// Client Secret. /// public string ClientSecret { get; init; } = string.Empty; /// - /// Only returns True if , , and are all not null or empty + /// Only returns True if , , + /// and are all not null or empty. /// public bool IsValid => !string.IsNullOrWhiteSpace(Name) @@ -51,8 +54,9 @@ public sealed record class KeyVaultConfig : IOptions this; /// - /// Get Azure Vault URI + /// Generate URI using . /// + /// Azure Vault URI. public Uri GetUri() => new($"https://{Name}.vault.azure.net/"); } diff --git a/src/Jeebs/Config/ConfigurationExtensions.cs b/src/Jeebs/Config/ConfigurationExtensions.cs index 6d7aea66b..0c690e03a 100644 --- a/src/Jeebs/Config/ConfigurationExtensions.cs +++ b/src/Jeebs/Config/ConfigurationExtensions.cs @@ -7,35 +7,40 @@ namespace Jeebs.Config; /// -/// IConfiguration extension methods +/// Extension methods for objects. /// public static class ConfigurationExtensions { /// - /// Caches configuration section values + /// Caches configuration section values. /// private static MemoryCache Cache { get; } = new(new MemoryCacheOptions()); /// - /// Return a configuration section from the cache as type T + /// Return a configuration section from the cache as type T. /// - /// Configuration settings type - /// IConfigurationRoot object - /// Section key + /// Configuration section type. + /// IConfigurationRoot object. + /// Section key. + /// Configuration Section as bound object. public static T GetSection(this IConfiguration config, string sectionKey) where T : class, new() => GetSection(config, sectionKey, true); /// - /// Return a configuration section as type T + /// Return a configuration section as type T. /// - /// Configuration settings type - /// IConfigurationRoot object - /// Section key - /// If true the config section will be retrieved from / added to the cache + /// Configuration settings type. + /// IConfigurationRoot object. + /// Section key. + /// If true the config section will be retrieved from / added to the cache. + /// Configuration Section as bound object. public static T GetSection(this IConfiguration config, string sectionKey, bool useCache) where T : class, new() { + static T getSection(IConfiguration config, string sectionKey) => + config.GetSection(JeebsConfig.GetKey(sectionKey)).Get() ?? new T(); + return useCache switch { true when Cache.GetOrCreate(typeof(T).FullName ?? typeof(T).Name, _ => getSection(config, sectionKey)) is T section => @@ -44,8 +49,5 @@ true when Cache.GetOrCreate(typeof(T).FullName ?? typeof(T).Name, _ => getSectio _ => getSection(config, sectionKey) }; - - static T getSection(IConfiguration config, string sectionKey) => - config.GetSection(JeebsConfig.GetKey(sectionKey)).Get() ?? new T(); } } diff --git a/src/Jeebs/Config/Db/DbConfig.cs b/src/Jeebs/Config/Db/DbConfig.cs index 0487ae4f9..8d0a08178 100644 --- a/src/Jeebs/Config/Db/DbConfig.cs +++ b/src/Jeebs/Config/Db/DbConfig.cs @@ -7,22 +7,22 @@ namespace Jeebs.Config.Db; /// -/// Database configuration +/// Database configuration. /// public sealed record class DbConfig : IOptions { /// - /// Path to database settings configuration section + /// Path to database settings configuration section. /// public static readonly string Key = JeebsConfig.Key + ":db"; /// - /// Default database connection name + /// Default database connection name. /// public string Default { get; init; } = string.Empty; /// - /// Authentication database connection name + /// Authentication database connection name. /// public string Authentication { @@ -36,7 +36,7 @@ public string Authentication private readonly string? authenticationConnectionValue; /// - /// Dictionary of database connections + /// Dictionary of database connections. /// public Dictionary Connections { get; init; } = []; @@ -45,47 +45,45 @@ public string Authentication this; /// - /// Retrieve default Connection + /// Retrieve default Connection. /// - /// - /// - /// - public DbConnectionConfig GetConnection() => - GetConnection(null); + public Result GetConnection() => + GetConnection(Default); /// - /// Retrieve Connection by name + /// Retrieve Connection by name. /// - /// [Optional] Connection name - /// - /// - /// - public DbConnectionConfig GetConnection(string? name) + /// Connection name. + public Result GetConnection(string name) { - // If name is null or empty, use Default connection - var connection = string.IsNullOrWhiteSpace(name) ? Default : name; - if (string.IsNullOrEmpty(connection)) + static Result fail(string message, params object[] args) => + R.Fail(nameof(DbConfig), nameof(GetConnection), message, args); + + // Name cannot be null or empty + if (string.IsNullOrEmpty(name)) { - throw new DefaultDbConnectionUndefinedException("Default database connection is not defined."); + return fail("Default database connection is not defined."); } - // Attempt to retrieve the connection + // The list of defined connections cannot be empty if (Connections.Count == 0) { - throw new NoDbConnectionsException("At least one database connection must be defined."); + return fail("At least one database connection must be defined."); } - if (Connections.TryGetValue(connection, out var config)) + // Attempt to retrieve the connection + if (Connections.TryGetValue(name, out var config)) { return config; } - throw new NamedDbConnectionNotFoundException(connection); + return fail("A connection named {ConnectionName} could not be found.", name); } /// - /// Retrieve the authentication database connection settings + /// Retrieve the authentication database Connection defined by . /// - public DbConnectionConfig GetAuthenticationConnection() => + /// The Authentication Connection configuration. + public Result GetAuthenticationConnection() => GetConnection(Authentication); } diff --git a/src/Jeebs/Config/Db/DbConnectionConfig.cs b/src/Jeebs/Config/Db/DbConnectionConfig.cs index f35b3b52a..0a91934af 100644 --- a/src/Jeebs/Config/Db/DbConnectionConfig.cs +++ b/src/Jeebs/Config/Db/DbConnectionConfig.cs @@ -6,22 +6,22 @@ namespace Jeebs.Config.Db; /// -/// Database connection configuration +/// Database connection configuration. /// public sealed record class DbConnectionConfig { /// - /// Database connection string + /// Database connection string. /// public string ConnectionString { get; init; } = string.Empty; /// - /// Database table prefix + /// Database table prefix. /// public string TablePrefix { get; init; } = string.Empty; /// - /// Additional settings required for configuring this database connection + /// Additional settings required for configuring this database connection. /// public Dictionary AdditionalSettings { get; init; } = []; } diff --git a/src/Jeebs/Config/Db/DefaultDbConnectionUndefinedException.cs b/src/Jeebs/Config/Db/DefaultDbConnectionUndefinedException.cs deleted file mode 100644 index b0308cfe8..000000000 --- a/src/Jeebs/Config/Db/DefaultDbConnectionUndefinedException.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; - -namespace Jeebs.Config.Db; - -/// -/// Default DB Connection Undefined -/// -public class DefaultDbConnectionUndefinedException : Exception -{ - /// - /// Create exception - /// - public DefaultDbConnectionUndefinedException() { } - - /// - /// Create exception - /// - /// - public DefaultDbConnectionUndefinedException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public DefaultDbConnectionUndefinedException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Db/NamedDbConnectionNotFoundException.cs b/src/Jeebs/Config/Db/NamedDbConnectionNotFoundException.cs deleted file mode 100644 index 573cf8075..000000000 --- a/src/Jeebs/Config/Db/NamedDbConnectionNotFoundException.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Db; - -/// -/// Named DB Connection Not Found -/// -public class NamedDbConnectionNotFoundException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Connection '{0}' was not found in configuration settings."); - - /// - /// Create exception - /// - public NamedDbConnectionNotFoundException() { } - - /// - /// Create exception - /// - /// - public NamedDbConnectionNotFoundException(string connection) : base(string.Format(CultureInfo.InvariantCulture, Format, connection)) { } - - /// - /// Create exception - /// - /// - /// - public NamedDbConnectionNotFoundException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Db/NoDbConnectionsException.cs b/src/Jeebs/Config/Db/NoDbConnectionsException.cs deleted file mode 100644 index 3130f9aac..000000000 --- a/src/Jeebs/Config/Db/NoDbConnectionsException.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; - -namespace Jeebs.Config.Db; - -/// -/// No DB Connections -/// -public class NoDbConnectionsException : Exception -{ - /// - /// Create exception - /// - public NoDbConnectionsException() { } - - /// - /// Create exception - /// - /// - public NoDbConnectionsException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public NoDbConnectionsException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/JeebsConfig.cs b/src/Jeebs/Config/JeebsConfig.cs index cd9bbf483..b74606c30 100644 --- a/src/Jeebs/Config/JeebsConfig.cs +++ b/src/Jeebs/Config/JeebsConfig.cs @@ -7,47 +7,47 @@ namespace Jeebs.Config; /// -/// Jeebs Configuration +/// Jeebs Configuration. /// public sealed record class JeebsConfig : IOptions { /// - /// Path to Jeebs settings configuration section + /// Path to Jeebs settings configuration section. /// public static readonly string Key = "jeebs"; /// - /// App congiguration + /// App congiguration. /// public App.AppConfig App { get; init; } = new(); /// - /// Azure configuration + /// Azure configuration. /// public Azure.AzureConfig Azure { get; init; } = new(); /// - /// Data configuration + /// Data configuration. /// public Db.DbConfig Db { get; init; } = new(); /// - /// Logging congiguration + /// Logging congiguration. /// public Logging.LoggingConfig Logging { get; init; } = new(); /// - /// Services configuration + /// Services configuration. /// public Services.ServicesConfig Services { get; init; } = new(); /// - /// Web congiguration + /// Web congiguration. /// public Web.WebConfig Web { get; init; } = new(); /// - /// WordPress configurations + /// WordPress configurations. /// public Dictionary Wp { get; init; } = []; @@ -56,9 +56,10 @@ public sealed record class JeebsConfig : IOptions this; /// - /// If key starts with ':', add Jeebs config prefix + /// If key starts with ':', add Jeebs config prefix. /// - /// Section key + /// Section key. + /// Full configuration settings key. public static string GetKey(string key) => key.StartsWith(':') ? Key + key : key; } diff --git a/src/Jeebs/Config/Logging/LoggingConfig.cs b/src/Jeebs/Config/Logging/LoggingConfig.cs index e29678d63..025569cf0 100644 --- a/src/Jeebs/Config/Logging/LoggingConfig.cs +++ b/src/Jeebs/Config/Logging/LoggingConfig.cs @@ -2,33 +2,33 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System.Collections.Generic; -using Jeebs.Logging; using Microsoft.Extensions.Options; +using Wrap.Logging; namespace Jeebs.Config.Logging; /// -/// Logging configuration +/// Logging configuration. /// public sealed record class LoggingConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = JeebsConfig.Key + ":logging"; /// - /// Overall Minimum LogLevel - no log event below this will be logged + /// Overall Minimum LogLevel - no log event below this will be logged. /// public LogLevel Minimum { get; init; } /// - /// Override minimum levels for sources beginning with dictionary key + /// Override minimum levels for sources beginning with dictionary key. /// public Dictionary Overrides { get; init; } = []; /// - /// List of providers - dictionary key is a service name + /// List of providers - dictionary key is a service name. /// public Dictionary Providers { get; init; } = []; diff --git a/src/Jeebs/Config/Logging/LoggingProviderConfig.cs b/src/Jeebs/Config/Logging/LoggingProviderConfig.cs index 348e4f380..eddbfba89 100644 --- a/src/Jeebs/Config/Logging/LoggingProviderConfig.cs +++ b/src/Jeebs/Config/Logging/LoggingProviderConfig.cs @@ -1,22 +1,22 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using Jeebs.Logging; +using Wrap.Logging; namespace Jeebs.Config.Logging; /// -/// Logging Provider +/// Logging Provider. /// public sealed record class LoggingProviderConfig { /// - /// Whether or not this provider is enabled + /// Whether or not this provider is enabled. /// public bool Enabled { get; init; } /// - /// This provider's minimum log level (overrides the default minimum level in main Logging section, if it's higher) + /// This provider's minimum log level (overrides the default minimum level in main Logging section, if it's higher). /// public LogLevel? Minimum { get; init; } } diff --git a/src/Jeebs/Config/Services/Console/ConsoleConfig.cs b/src/Jeebs/Config/Services/Console/ConsoleConfig.cs index 83893da87..00add7e0f 100644 --- a/src/Jeebs/Config/Services/Console/ConsoleConfig.cs +++ b/src/Jeebs/Config/Services/Console/ConsoleConfig.cs @@ -6,17 +6,17 @@ namespace Jeebs.Config.Services.Console; /// -/// Console configuration +/// Console configuration. /// public sealed record class ConsoleConfig : IOptions, IServiceConfig { /// - /// Override default template + /// Override default template. /// public string? Template { get; init; } /// - /// Whether or not to add a prefix to the output + /// Whether or not to add a prefix to the output. /// public bool AddPrefix { get; init; } = true; diff --git a/src/Jeebs/Config/Services/IServiceConfig.cs b/src/Jeebs/Config/Services/IServiceConfig.cs index 6ba444e7d..8220d53ce 100644 --- a/src/Jeebs/Config/Services/IServiceConfig.cs +++ b/src/Jeebs/Config/Services/IServiceConfig.cs @@ -1,15 +1,15 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 namespace Jeebs.Config; /// -/// Service configuration interface +/// Service configuration interface. /// public interface IServiceConfig { /// - /// Whether or not this service configuration is valid + /// Whether or not this service configuration is valid. /// bool IsValid { get; } } diff --git a/src/Jeebs/Config/Services/IWebhookServiceConfig.cs b/src/Jeebs/Config/Services/IWebhookServiceConfig.cs index 2dc1103fc..aaab1a081 100644 --- a/src/Jeebs/Config/Services/IWebhookServiceConfig.cs +++ b/src/Jeebs/Config/Services/IWebhookServiceConfig.cs @@ -1,15 +1,15 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 namespace Jeebs.Config; /// -/// Webhook service configuration interface +/// Webhook service configuration interface. /// public interface IWebhookServiceConfig : IServiceConfig { /// - /// Webhook URI + /// Webhook URI. /// string Webhook { get; } } diff --git a/src/Jeebs/Config/Services/InvalidServiceConfigurationException.cs b/src/Jeebs/Config/Services/InvalidServiceConfigurationException.cs deleted file mode 100644 index fc0d9ff32..000000000 --- a/src/Jeebs/Config/Services/InvalidServiceConfigurationException.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Services; - -/// -/// Invalid Service Configuration -/// -public class InvalidServiceConfigurationException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Service configuration '{0}' in {1} collection is not valid."); - - /// - /// Create exception - /// - public InvalidServiceConfigurationException() { } - - /// - /// Create exception - /// - /// - public InvalidServiceConfigurationException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public InvalidServiceConfigurationException(string message, Exception inner) : base(message, inner) { } - - /// - /// Create exception - /// - /// - /// - public InvalidServiceConfigurationException(string name, Type type) : this(string.Format(CultureInfo.InvariantCulture, Format, name, type)) { } -} diff --git a/src/Jeebs/Config/Services/InvalidServiceDefinitionException.cs b/src/Jeebs/Config/Services/InvalidServiceDefinitionException.cs deleted file mode 100644 index eeca22803..000000000 --- a/src/Jeebs/Config/Services/InvalidServiceDefinitionException.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Services; - -/// -/// Invalid Service Definition -/// -public class InvalidServiceDefinitionException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Invalid service definition '{0}': should be [service_type].[service_name]."); - - /// - /// Create exception - /// - public InvalidServiceDefinitionException() { } - - /// - /// Create exception - /// - /// - public InvalidServiceDefinitionException(string definition) : base(string.Format(CultureInfo.InvariantCulture, Format, definition)) { } - - /// - /// Create exception - /// - /// - /// - public InvalidServiceDefinitionException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Services/Seq/SeqConfig.cs b/src/Jeebs/Config/Services/Seq/SeqConfig.cs index 3e1f100a2..5ac45d62e 100644 --- a/src/Jeebs/Config/Services/Seq/SeqConfig.cs +++ b/src/Jeebs/Config/Services/Seq/SeqConfig.cs @@ -7,7 +7,7 @@ namespace Jeebs.Config.Services.Seq; /// -/// Seq configuration +/// Seq configuration. /// public sealed record class SeqConfig : IOptions, IWebhookServiceConfig { @@ -16,12 +16,12 @@ public sealed record class SeqConfig : IOptions, IWebhookServiceConfi $"{Server}/api/events/raw?clef"; /// - /// Seq Server URI + /// Seq Server URI. /// public string Server { get; init; } = string.Empty; /// - /// Seq Server API Key + /// Seq Server API Key. /// public string ApiKey { get; init; } = string.Empty; diff --git a/src/Jeebs/Config/Services/ServicesConfig.cs b/src/Jeebs/Config/Services/ServicesConfig.cs index ac933ad1a..c134d0147 100644 --- a/src/Jeebs/Config/Services/ServicesConfig.cs +++ b/src/Jeebs/Config/Services/ServicesConfig.cs @@ -8,27 +8,27 @@ namespace Jeebs.Config.Services; /// -/// Third-party services configuration +/// Third-party services configuration. /// public sealed record class ServicesConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = JeebsConfig.Key + ":services"; /// - /// Console configurations + /// Console configurations. /// public Dictionary Console { get; init; } = []; /// - /// Seq configurations + /// Seq configurations. /// public Dictionary Seq { get; init; } = []; /// - /// Slack configurations + /// Slack configurations. /// public Dictionary Slack { get; init; } = []; @@ -37,83 +37,78 @@ public sealed record class ServicesConfig : IOptions this; /// - /// Get a service configuration from the definition - /// Definition must be in the format service_type.service_name + /// Get a service configuration by definition. /// - /// - /// Service definition - in format service_type.service_name - public IServiceConfig GetServiceConfig(string definition) => - SplitDefinition(definition) switch - { - ("console", string name) => - GetServiceConfig(c => c.Console, name), + /// Configuration definition - in format service_type.service_name + /// Service configuration. + public Result GetServiceConfig(string definition) => + SplitDefinition(definition).Match( + none: () => R.Fail(nameof(ServicesConfig), nameof(GetServiceConfig), + "Invalid service definition: '{Definition}'.", definition + ), + some: x => x switch + { + ("console", string name) => + GetServiceConfig(c => c.Console, name), - ("seq", string name) => - GetServiceConfig(c => c.Seq, name), + ("seq", string name) => + GetServiceConfig(c => c.Seq, name), - ("slack", string name) => - GetServiceConfig(c => c.Slack, name), + ("slack", string name) => + GetServiceConfig(c => c.Slack, name), - (string type, _) => - throw new UnsupportedServiceException(type) - }; + (string type, _) => + R.Fail(nameof(ServicesConfig), nameof(GetServiceConfig), + "Unsupported service type: {Type}.", type + ) + } + ); /// - /// Get a named service configuration - /// Checks if it is valid before returning it + /// Get a named service configuration. /// - /// - /// - /// - /// The service collection to use - /// The name of the service to get - public TConfig GetServiceConfig(Func> getCollection, string name) - where TConfig : IServiceConfig, new() - { - var services = getCollection(this); - if (!services.TryGetValue(name, out var config)) - { - return new TConfig(); - } - - if (!config.IsValid) - { - throw new InvalidServiceConfigurationException(name, typeof(TConfig)); - } + /// Service Config type + /// The service collection to use. + /// The name of the service to get. + /// Service configuration. + public Result GetServiceConfig(Func> getCollection, string name) + where T : IServiceConfig, new() => + getCollection(this).GetValueOrNone(name).Match( + none: () => new T(), + some: x => x.IsValid switch + { + false => + R.Fail(nameof(ServicesConfig), nameof(GetServiceConfig), + "Definition of {Type} service named '{Name}' is invalid.", typeof(T).Name, name + ), - return config; - } + true => + R.Wrap((IServiceConfig)x) + } + ); /// - /// Split a service definition - /// Definition must be in the format service_type.service_name + /// Split a service definition. /// - /// - /// Service definition - in format service_type.service_name - public static (string type, string name) SplitDefinition(string definition) - { - if (string.IsNullOrWhiteSpace(definition)) + /// Service definition - in format service_type.service_name. + /// Definition tuple. + public static Maybe<(string type, string name)> SplitDefinition(string definition) => + string.IsNullOrWhiteSpace(definition) switch { - throw new InvalidServiceDefinitionException(definition); - } + false => + definition.Split('.') switch + { + var x when x.Length == 1 => + (x[0], string.Empty), - try - { - return definition.Split('.') switch - { - var x when x.Length == 1 => - (x[0], string.Empty), + var x when x.Length == 2 => + (x[0], x[1]), - var x when x.Length == 2 => - (x[0], x[1]), + _ => + M.None + }, - _ => - throw new InvalidServiceDefinitionException(definition) - }; - } - catch (Exception) - { - throw new InvalidServiceDefinitionException(definition); - } - } + true => + M.None + }; } diff --git a/src/Jeebs/Config/Services/Slack/SlackConfig.cs b/src/Jeebs/Config/Services/Slack/SlackConfig.cs index d57553a3c..d75bec3c9 100644 --- a/src/Jeebs/Config/Services/Slack/SlackConfig.cs +++ b/src/Jeebs/Config/Services/Slack/SlackConfig.cs @@ -7,7 +7,7 @@ namespace Jeebs.Config.Services.Slack; /// -/// Slack configuration +/// Slack configuration. /// public sealed record class SlackConfig : IOptions, IWebhookServiceConfig { @@ -15,7 +15,7 @@ public sealed record class SlackConfig : IOptions, IWebhookServiceC public string Webhook { get; init; } = string.Empty; /// - /// Whether or not to add attachments to a message (error type and timestamp) + /// Whether or not to add attachments to a message (error type and timestamp). /// public bool ShowAttachments { get; init; } diff --git a/src/Jeebs/Config/Services/UnknownServiceException.cs b/src/Jeebs/Config/Services/UnknownServiceException.cs deleted file mode 100644 index fafbd64fb..000000000 --- a/src/Jeebs/Config/Services/UnknownServiceException.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Services; - -/// -/// Unknown Service -/// -public class UnknownServiceException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Unknown service '{0}' in {1} collection."); - - /// - /// Create exception - /// - public UnknownServiceException() { } - - /// - /// Create exception - /// - /// - public UnknownServiceException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public UnknownServiceException(string message, Exception inner) : base(message, inner) { } - - /// - /// Create exception - /// - /// - /// - public UnknownServiceException(string name, Type type) : this(string.Format(CultureInfo.InvariantCulture, Format, name, type)) { } -} diff --git a/src/Jeebs/Config/Services/UnsupportedServiceException.cs b/src/Jeebs/Config/Services/UnsupportedServiceException.cs deleted file mode 100644 index 1a6d7d1f0..000000000 --- a/src/Jeebs/Config/Services/UnsupportedServiceException.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Services; - -/// -/// Unsupported Service -/// -public class UnsupportedServiceException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Unsupported service type '{0}'."); - - /// - /// Create exception - /// - public UnsupportedServiceException() { } - - /// - /// Create exception - /// - /// Service type - public UnsupportedServiceException(string type) : base(string.Format(CultureInfo.InvariantCulture, Format, type)) { } - - /// - /// Create exception - /// - /// - /// - public UnsupportedServiceException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Web/Auth/AuthConfig.cs b/src/Jeebs/Config/Web/Auth/AuthConfig.cs index 95b9f32fc..8f31d50b3 100644 --- a/src/Jeebs/Config/Web/Auth/AuthConfig.cs +++ b/src/Jeebs/Config/Web/Auth/AuthConfig.cs @@ -6,37 +6,37 @@ namespace Jeebs.Config.Web.Auth; /// -/// Jeebs Authentication and Authorisation Configuraiton +/// Jeebs Authentication and Authorisation configuration. /// public sealed record class AuthConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = WebConfig.Key + ":auth"; /// - /// Whether or not auth is enabled + /// Whether or not auth is enabled. /// public bool Enabled { get; init; } /// - /// Authentication scheme + /// Authentication scheme. /// public AuthScheme? Scheme { get; init; } /// - /// Path to the login page + /// Path to the login page. /// public string? LoginPath { get; init; } /// - /// Path to the access denied page + /// Path to the access denied page. /// public string? AccessDeniedPath { get; init; } /// - /// JwtConfig + /// JwtConfig. /// public Jwt.JwtConfig Jwt { get; init; } = new(); diff --git a/src/Jeebs/Config/Web/Auth/AuthNotEnabledException.cs b/src/Jeebs/Config/Web/Auth/AuthNotEnabledException.cs deleted file mode 100644 index b090a1452..000000000 --- a/src/Jeebs/Config/Web/Auth/AuthNotEnabledException.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; - -namespace Jeebs.Config.Web.Auth; - -/// -/// Adding auth when auth is not enabled in configuration -/// -public sealed class AuthNotEnabledException : Exception -{ - /// - /// Create exception - /// - public AuthNotEnabledException() : this("You need to enable auth in JSON configuration settings.") { } - - /// - /// Create exception - /// - /// - public AuthNotEnabledException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public AuthNotEnabledException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Web/Auth/AuthScheme.cs b/src/Jeebs/Config/Web/Auth/AuthScheme.cs index 31d606a09..69038c98f 100644 --- a/src/Jeebs/Config/Web/Auth/AuthScheme.cs +++ b/src/Jeebs/Config/Web/Auth/AuthScheme.cs @@ -4,17 +4,17 @@ namespace Jeebs.Config.Web.Auth; /// -/// Supported authentication schemes +/// Supported authentication schemes. /// public enum AuthScheme { /// - /// Cookies authentication + /// Cookies authentication. /// Cookies = 1 << 0, /// - /// JWT authentication + /// JWT authentication. /// Jwt = 1 << 1 } diff --git a/src/Jeebs/Config/Web/Auth/Jwt/InvalidJwtConfigurationException.cs b/src/Jeebs/Config/Web/Auth/Jwt/InvalidJwtConfigurationException.cs deleted file mode 100644 index 7ec77f38f..000000000 --- a/src/Jeebs/Config/Web/Auth/Jwt/InvalidJwtConfigurationException.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; - -namespace Jeebs.Config.Web.Auth.Jwt; - -/// -/// Invalid JWT configuration -/// -public class InvalidJwtConfigurationException : Exception -{ - /// - /// Create exception - /// - public InvalidJwtConfigurationException() { } - - /// - /// Create exception - /// - /// - public InvalidJwtConfigurationException(string message) : base(message) { } - - /// - /// Create exception - /// - /// - /// - public InvalidJwtConfigurationException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Web/Auth/Jwt/JwtConfig.cs b/src/Jeebs/Config/Web/Auth/Jwt/JwtConfig.cs index f137f1bcf..4647f0112 100644 --- a/src/Jeebs/Config/Web/Auth/Jwt/JwtConfig.cs +++ b/src/Jeebs/Config/Web/Auth/Jwt/JwtConfig.cs @@ -6,42 +6,42 @@ namespace Jeebs.Config.Web.Auth.Jwt; /// -/// JSON Web Tokens (JWT) configuration +/// JSON Web Tokens (JWT) configuration. /// public sealed record class JwtConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = AuthConfig.Key + ":jwt"; /// - /// The generated signing key (key is rotated each time the application restarts) + /// The generated signing key (key is rotated each time the application restarts). /// public string SigningKey { get; init; } = string.Empty; /// - /// The generated signing key (key is rotated each time the application restarts) + /// The generated signing key (key is rotated each time the application restarts). /// public string? EncryptingKey { get; init; } /// - /// URL of application issuing this token + /// URL of application issuing this token. /// public string Issuer { get; init; } = string.Empty; /// - /// URL of application using this token + /// URL of application using this token. /// public string Audience { get; init; } = string.Empty; /// - /// Number of hours the token will be valid for + /// Number of hours the token will be valid for. /// public int ValidForHours { get; init; } = 1; /// - /// Whether or not the configuration is valid + /// Whether or not the configuration is valid. /// public bool IsValid => !string.IsNullOrEmpty(SigningKey) diff --git a/src/Jeebs/Config/Web/Auth/UnsupportedAuthSchemeException.cs b/src/Jeebs/Config/Web/Auth/UnsupportedAuthSchemeException.cs deleted file mode 100644 index ae7cc7503..000000000 --- a/src/Jeebs/Config/Web/Auth/UnsupportedAuthSchemeException.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -using System; -using System.Globalization; -using System.Text; - -namespace Jeebs.Config.Web.Auth; - -/// -/// Unknown / unsupported authentication scheme -/// -public sealed class UnsupportedAuthSchemeException : Exception -{ - /// - /// Exception message format - /// - public static readonly CompositeFormat Format = CompositeFormat.Parse("Unsupported auth scheme '{0}'."); - - /// - /// Create exception - /// - public UnsupportedAuthSchemeException() { } - - /// - /// Create exception - /// - /// Service type - public UnsupportedAuthSchemeException(string scheme) : base(string.Format(CultureInfo.InvariantCulture, Format, scheme)) { } - - /// - /// Create exception - /// - /// - /// - public UnsupportedAuthSchemeException(string message, Exception inner) : base(message, inner) { } -} diff --git a/src/Jeebs/Config/Web/Redirections/RedirectionsConfig.cs b/src/Jeebs/Config/Web/Redirections/RedirectionsConfig.cs index 1778019c6..c440289e0 100644 --- a/src/Jeebs/Config/Web/Redirections/RedirectionsConfig.cs +++ b/src/Jeebs/Config/Web/Redirections/RedirectionsConfig.cs @@ -7,12 +7,12 @@ namespace Jeebs.Config.Web.Redirections; /// -/// Redirections configuration +/// Redirections configuration. /// public sealed class RedirectionsConfig : Dictionary, IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = WebConfig.Key + ":redirections"; diff --git a/src/Jeebs/Config/Web/Verification/VerificationConfig.cs b/src/Jeebs/Config/Web/Verification/VerificationConfig.cs index 6661e72d6..747b52ad7 100644 --- a/src/Jeebs/Config/Web/Verification/VerificationConfig.cs +++ b/src/Jeebs/Config/Web/Verification/VerificationConfig.cs @@ -7,17 +7,17 @@ namespace Jeebs.Config.Web.Verification; /// -/// Site Verification Configuration +/// Site Verification Configuration. /// public sealed record class VerificationConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = WebConfig.Key + ":verification"; /// - /// Google Site Verification page + /// Google Site Verification page. /// public string? Google { @@ -31,7 +31,7 @@ public string? Google private readonly string? googleCode; /// - /// True if there are any verification configurations + /// True if there are any verification configurations. /// public bool Any => Google is not null; diff --git a/src/Jeebs/Config/Web/WebConfig.cs b/src/Jeebs/Config/Web/WebConfig.cs index 639a2d636..085dda41b 100644 --- a/src/Jeebs/Config/Web/WebConfig.cs +++ b/src/Jeebs/Config/Web/WebConfig.cs @@ -6,27 +6,27 @@ namespace Jeebs.Config.Web; /// -/// Configuration options for Web Apps +/// Configuration options for Web Apps. /// public sealed record class WebConfig : IOptions { /// - /// Path to this configuration section + /// Path to this configuration section. /// public static readonly string Key = JeebsConfig.Key + ":web"; /// - /// Authentication and Authorisation configuration + /// Authentication and Authorisation configuration. /// public Auth.AuthConfig Auth { get; init; } = new(); /// - /// RedirectionsConfig + /// RedirectionsConfig. /// public Redirections.RedirectionsConfig Redirections { get; init; } = []; /// - /// SiteVerificationConfig + /// SiteVerificationConfig. /// public Verification.VerificationConfig Verification { get; init; } = new(); diff --git a/src/Jeebs/Config/WordPress/WpConfig.cs b/src/Jeebs/Config/WordPress/WpConfig.cs index 7cb1b828b..b5dc06dbe 100644 --- a/src/Jeebs/Config/WordPress/WpConfig.cs +++ b/src/Jeebs/Config/WordPress/WpConfig.cs @@ -6,38 +6,38 @@ namespace Jeebs.Config.WordPress; /// -/// WordPress configuration +/// WordPress configuration. /// public record class WpConfig : IOptions { /// - /// Path to WordPress settings configuration section + /// Path to WordPress settings configuration section. /// public static readonly string Key = JeebsConfig.Key + ":wp"; /// - /// Database connection name (accessed via main Jeebs DB settings section) - /// If empty, will attempt to use the default connection (as defined in main Jeebs DB settings section) + /// Database connection name (accessed via main Jeebs DB settings section). + /// If empty, will attempt to use the default connection (as defined in main Jeebs DB settings section). /// public string Db { get; init; } = string.Empty; /// - /// Overrides the table prefix in the DB connection settings + /// Overrides the table prefix in the DB connection settings. /// public string TablePrefix { get; init; } = string.Empty; /// - /// /wp-content/uploads URL (for replacing with local URL) + /// /wp-content/uploads URL (for replacing with local URL). /// public string UploadsUrl { get; init; } = string.Empty; /// - /// /wp-content/uploads path (to access files directly) + /// /wp-content/uploads path (to access files directly). /// public string UploadsPath { get; init; } = string.Empty; /// - /// Files URL (alias to hide wp-content/uploads directory) + /// Files URL (alias to hide wp-content/uploads directory). /// public string VirtualUploadsUrl { get; init; } = string.Empty; diff --git a/src/Jeebs/Constants/BibleBooks.cs b/src/Jeebs/Constants/BibleBooks.cs index f12d5ece6..d544da1c5 100644 --- a/src/Jeebs/Constants/BibleBooks.cs +++ b/src/Jeebs/Constants/BibleBooks.cs @@ -1,475 +1,480 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System.Collections.Generic; -using System.Linq; namespace Jeebs.Constants; /// -/// Bible Books +/// Bible Books. /// public static class BibleBooks { /// - /// Genesis + /// Genesis. /// public static string Genesis => "Genesis"; /// - /// Exodus + /// Exodus. /// public static string Exodus => "Exodus"; /// - /// Leviticus + /// Leviticus. /// public static string Leviticus => "Leviticus"; /// - /// Numbers + /// Numbers. /// public static string Numbers => "Numbers"; /// - /// Deuteronomy + /// Deuteronomy. /// public static string Deuteronomy => "Deuteronomy"; /// - /// Joshua + /// Joshua. /// public static string Joshua => "Joshua"; /// - /// Judges + /// Judges. /// public static string Judges => "Judges"; /// - /// Ruth + /// Ruth. /// public static string Ruth => "Ruth"; /// - /// 1 Samuel + /// 1 Samuel. /// public static string FirstSamuel => "1 Samuel"; /// - /// 2 Samuel + /// 2 Samuel. /// public static string SecondSamuel => "2 Samuel"; /// - /// 1 Kings + /// 1 Kings. /// public static string FirstKings => "1 Kings"; /// - /// 2 Kings + /// 2 Kings. /// public static string SecondKings => "2 Kings"; /// - /// 1 Chronicles + /// 1 Chronicles. /// public static string FirstChronicles => "1 Chronicles"; /// - /// 2 Chronicles + /// 2 Chronicles. /// public static string SecondChronicles => "2 Chronicles"; /// - /// Ezra + /// Ezra. /// public static string Ezra => "Ezra"; /// - /// Nehemiah + /// Nehemiah. /// public static string Nehemiah => "Nehemiah"; /// - /// Esther + /// Esther. /// public static string Esther => "Esther"; /// - /// Job + /// Job. /// public static string Job => "Job"; /// - /// Psalms + /// Psalms. /// public static string Psalms => "Psalms"; /// - /// Proverbs + /// Proverbs. /// public static string Proverbs => "Proverbs"; /// - /// Ecclesiastes + /// Ecclesiastes. /// public static string Ecclesiastes => "Ecclesiastes"; /// - /// SongOfSongs + /// Song of Songs. /// public static string SongOfSongs => "Song of Songs"; /// - /// Isaiah + /// Isaiah. /// public static string Isaiah => "Isaiah"; /// - /// Jeremiah + /// Jeremiah. /// public static string Jeremiah => "Jeremiah"; /// - /// Lamentations + /// Lamentations. /// public static string Lamentations => "Lamentations"; /// - /// Ezekiel + /// Ezekiel. /// public static string Ezekiel => "Ezekiel"; /// - /// Daniel + /// Daniel. /// public static string Daniel => "Daniel"; /// - /// Hosea + /// Hosea. /// public static string Hosea => "Hosea"; /// - /// Joel + /// Joel. /// public static string Joel => "Joel"; /// - /// Amos + /// Amos. /// public static string Amos => "Amos"; /// - /// Obadiah + /// Obadiah. /// public static string Obadiah => "Obadiah"; /// - /// Jonah + /// Jonah. /// public static string Jonah => "Jonah"; /// - /// Micah + /// Micah. /// public static string Micah => "Micah"; /// - /// Nahum + /// Nahum. /// public static string Nahum => "Nahum"; /// - /// Habakkuk + /// Habakkuk. /// public static string Habakkuk => "Habakkuk"; /// - /// Zephaniah + /// Zephaniah. /// public static string Zephaniah => "Zephaniah"; /// - /// Haggai + /// Haggai. /// public static string Haggai => "Haggai"; /// - /// Zechariah + /// Zechariah. /// public static string Zechariah => "Zechariah"; /// - /// Malachi + /// Malachi. /// public static string Malachi => "Malachi"; /// - /// Matthew + /// Matthew. /// public static string Matthew => "Matthew"; /// - /// Mark + /// Mark. /// public static string Mark => "Mark"; /// - /// Luke + /// Luke. /// public static string Luke => "Luke"; /// - /// John + /// John. /// public static string John => "John"; /// - /// Acts + /// Acts. /// public static string Acts => "Acts"; /// - /// Romans + /// Romans. /// public static string Romans => "Romans"; /// - /// 1 Corinthians + /// 1 Corinthians. /// public static string FirstCorinthians => "1 Corinthians"; /// - /// 2 Corinthians + /// 2 Corinthians. /// public static string SecondCorinthians => "2 Corinthians"; /// - /// Galations + /// Galatians. /// public static string Galatians => "Galatians"; /// - /// Ephesians + /// Ephesians. /// public static string Ephesians => "Ephesians"; /// - /// Philippians + /// Philippians. /// public static string Philippians => "Philippians"; /// - /// Colossians + /// Colossians. /// public static string Colossians => "Colossians"; /// - /// 1 Thessalonians + /// 1 Thessalonians. /// public static string FirstThessalonians => "1 Thessalonians"; /// - /// 2 Thessalonians + /// 2 Thessalonians. /// public static string SecondThessalonians => "2 Thessalonians"; /// - /// 1 Timothy + /// 1 Timothy. /// public static string FirstTimothy => "1 Timothy"; /// - /// 2 Timothy + /// 2 Timothy. /// public static string SecondTimothy => "2 Timothy"; /// - /// Titus + /// Titus. /// public static string Titus => "Titus"; /// - /// Philemon + /// Philemon. /// public static string Philemon => "Philemon"; /// - /// Hebrews + /// Hebrews. /// public static string Hebrews => "Hebrews"; /// - /// James + /// James. /// public static string James => "James"; /// - /// 1 Peter + /// 1 Peter. /// public static string FirstPeter => "1 Peter"; /// - /// 2 Peter + /// 2 Peter. /// public static string SecondPeter => "2 Peter"; /// - /// 1 John + /// 1 John. /// public static string FirstJohn => "1 John"; /// - /// 2 John + /// 2 John. /// public static string SecondJohn => "2 John"; /// - /// 3 John + /// 3 John. /// public static string ThirdJohn => "3 John"; /// - /// Jude + /// Jude. /// public static string Jude => "Jude"; /// - /// Revelation + /// Revelation. /// public static string Revelation => "Revelation"; /// - /// Books of the Law + /// Books of the Law. /// public static List Law => - new(new[] { Genesis, Exodus, Leviticus, Numbers, Deuteronomy }); + new([Genesis, Exodus, Leviticus, Numbers, Deuteronomy]); /// - /// History Books + /// History Books. /// public static List History => - new(new[] { Joshua, Judges, Ruth, FirstSamuel, SecondSamuel, FirstKings, SecondKings, FirstChronicles, SecondChronicles, Ezra, Nehemiah, Esther }); + new([Joshua, Judges, Ruth, FirstSamuel, SecondSamuel, FirstKings, SecondKings, FirstChronicles, SecondChronicles, Ezra, Nehemiah, Esther]); /// /// Wisdom Literature /// public static List Wisdom => - new(new[] { Job, Psalms, Proverbs, Ecclesiastes, SongOfSongs }); + new([Job, Psalms, Proverbs, Ecclesiastes, SongOfSongs]); /// - /// Major Prophets + /// Major Prophets. /// public static List MajorProphets => - new(new[] { Isaiah, Jeremiah, Lamentations, Ezekiel, Daniel }); + new([Isaiah, Jeremiah, Lamentations, Ezekiel, Daniel]); /// - /// Minor Prophets + /// Minor Prophets. /// public static List MinorProphets => - new(new[] { Hosea, Joel, Amos, Obadiah, Jonah, Micah, Nahum, Habakkuk, Zephaniah, Haggai, Zechariah, Malachi }); + new([Hosea, Joel, Amos, Obadiah, Jonah, Micah, Nahum, Habakkuk, Zephaniah, Haggai, Zechariah, Malachi]); /// - /// Old Testament + /// Old Testament. /// public static List OldTestament => - Law.Concat(History).Concat(Wisdom).Concat(MajorProphets).Concat(MinorProphets).ToList(); + [.. Law, .. History, .. Wisdom, .. MajorProphets, .. MinorProphets]; /// - /// Gospels + /// Gospels. /// public static List Gospels => - new(new[] { Matthew, Mark, Luke, John }); + new([Matthew, Mark, Luke, John]); /// - /// Pauline Letters + /// Gospels and Acts. + /// + public static List GospelsAndActs => + new([.. Gospels, Acts]); + + /// + /// Pauline Letters. /// public static List PaulineLetters => - new(new[] { Romans, FirstCorinthians, SecondCorinthians, Galatians, Ephesians, Philippians, Colossians, FirstThessalonians, SecondThessalonians, FirstTimothy, SecondTimothy, Titus, Philemon }); + new([Romans, FirstCorinthians, SecondCorinthians, Galatians, Ephesians, Philippians, Colossians, FirstThessalonians, SecondThessalonians, FirstTimothy, SecondTimothy, Titus, Philemon]); /// - /// Epistles + /// Epistles. /// public static List Epistles => - new(new[] { Acts, Romans, FirstCorinthians, SecondCorinthians, Galatians, Ephesians, Philippians, Colossians, FirstThessalonians, SecondThessalonians, FirstTimothy, SecondTimothy, Titus, Philemon, Hebrews, James, FirstPeter, SecondPeter, FirstJohn, SecondJohn, ThirdJohn, Jude, Revelation }); + new([.. PaulineLetters, Hebrews, James, FirstPeter, SecondPeter, FirstJohn, SecondJohn, ThirdJohn, Jude, Revelation]); /// - /// New Testament + /// New Testament. /// public static List NewTestament => - Gospels.Concat(Epistles).ToList(); + [.. GospelsAndActs, .. Epistles]; /// - /// All Books + /// All Books. /// public static List All => - OldTestament.Concat(NewTestament).ToList(); + [.. OldTestament, .. NewTestament]; } diff --git a/src/Jeebs/Constants/UnPluralisables.cs b/src/Jeebs/Constants/UnPluralisables.cs index 11b14a86d..17bf8e03f 100644 --- a/src/Jeebs/Constants/UnPluralisables.cs +++ b/src/Jeebs/Constants/UnPluralisables.cs @@ -1,4 +1,4 @@ -// Jeebs Rapid Application Development +// Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System.Collections.Generic; @@ -6,16 +6,15 @@ namespace Jeebs.Constants; /// -/// Unpluralisable words +/// Unpluralisable words. /// public static class UnPluralisables { /// - /// Return all unpluralisable words + /// Return all unpluralisable words. /// public static List All => - new() - { + [ "aircraft", "deer", "equipment", @@ -28,5 +27,5 @@ public static class UnPluralisables "species", "swine", "trout", - }; + ]; } diff --git a/src/Jeebs/DateTimeExtensions.cs b/src/Jeebs/DateTimeExtensions.cs index fa8359283..e108e14ef 100644 --- a/src/Jeebs/DateTimeExtensions.cs +++ b/src/Jeebs/DateTimeExtensions.cs @@ -7,7 +7,7 @@ namespace Jeebs; /// -/// DateTime Extensions +/// Extension methods for objects. /// public static class DateTimeExtensions { diff --git a/src/Jeebs/Extensions/StringExtensions.ConvertCurlyQuotes.cs b/src/Jeebs/Extensions/StringExtensions.ConvertCurlyQuotes.cs index 648acca24..67d86fbee 100644 --- a/src/Jeebs/Extensions/StringExtensions.ConvertCurlyQuotes.cs +++ b/src/Jeebs/Extensions/StringExtensions.ConvertCurlyQuotes.cs @@ -7,14 +7,31 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { + /// + public static string ConvertCurlyQuotes(this string @this) => + ConvertCurlyQuotes(@this, "‘", "’", "“", "”"); + + /// + public static string ConvertCurlyQuotes(this string @this, string ls) => + ConvertCurlyQuotes(@this, ls, "’", "“", "”"); + + /// + public static string ConvertCurlyQuotes(this string @this, string ls, string rs) => + ConvertCurlyQuotes(@this, ls, rs, "“", "”"); + + /// + public static string ConvertCurlyQuotes(this string @this, string ls, string rs, string ld) => + ConvertCurlyQuotes(@this, ls, rs, ld, "”"); + /// - /// Convert straight quotes to curly quotes + /// Convert straight quotes to curly quotes. /// - /// Input string - /// Left single quote mark - /// Right single quote mark - /// Left double quote mark - /// Right double quote mark + /// Input string. + /// Left single quote mark. + /// Right single quote mark. + /// Left double quote mark. + /// Right double quote mark. + /// with straight quotes converted to curly quotes. public static string ConvertCurlyQuotes(this string @this, string ls, string rs, string ld, string rd) => Modify(@this, () => { @@ -24,29 +41,17 @@ public static string ConvertCurlyQuotes(this string @this, string ls, string rs, .Replace("'", "'"); // Use regular expression to replace single quotes at the end of words - var singleQuote = SingleQuoteRegex(); - s = singleQuote.Replace(s, $"$1{ls}").Replace("'", rs); + s = SingleQuoteRegex() + .Replace(s, $"$1{ls}") + .Replace("'", rs); // Use regular expression to replace double quote at the end of words - var doubleQuote = DoubleQuoteRegex(); - return doubleQuote.Replace(s, $"$1{ld}").Replace("\"", rd); - }); + s = DoubleQuoteRegex() + .Replace(s, $"$1{ld}") + .Replace("\"", rd); - /// - public static string ConvertCurlyQuotes(this string @this, string ls, string rs, string ld) => - ConvertCurlyQuotes(@this, ls, rs, ld, "”"); - - /// - public static string ConvertCurlyQuotes(this string @this, string ls, string rs) => - ConvertCurlyQuotes(@this, ls, rs, "“", "”"); - - /// - public static string ConvertCurlyQuotes(this string @this, string ls) => - ConvertCurlyQuotes(@this, ls, "’", "“", "”"); - - /// - public static string ConvertCurlyQuotes(this string @this) => - ConvertCurlyQuotes(@this, "‘", "’", "“", "”"); + return s; + }); [GeneratedRegex("(\\s|^)'")] private static partial Regex SingleQuoteRegex(); diff --git a/src/Jeebs/Extensions/StringExtensions.ConvertInnerHtmlQuotes.cs b/src/Jeebs/Extensions/StringExtensions.ConvertInnerHtmlQuotes.cs index 817a6bc4a..2b970a74d 100644 --- a/src/Jeebs/Extensions/StringExtensions.ConvertInnerHtmlQuotes.cs +++ b/src/Jeebs/Extensions/StringExtensions.ConvertInnerHtmlQuotes.cs @@ -9,9 +9,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Convert straight quotes to curly quotes, but not inside HTML tags / attributes + /// Convert straight quotes to curly quotes, but not inside HTML tags / attributes. /// - /// Input string + /// Input string. + /// with straight quotes converted to curly quotes except inside HTML. public static string ConvertInnerHtmlQuotes(this string @this) => Modify(@this, () => { diff --git a/src/Jeebs/Extensions/StringExtensions.EndWith.cs b/src/Jeebs/Extensions/StringExtensions.EndWith.cs index da0648cf0..be249967c 100644 --- a/src/Jeebs/Extensions/StringExtensions.EndWith.cs +++ b/src/Jeebs/Extensions/StringExtensions.EndWith.cs @@ -8,18 +8,20 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Ensure that an input string ends with a single defined character + /// Ensure that an input string ends with a single defined character. /// - /// The input string - /// The character to end the string with + /// The input string. + /// The character to end the string with. + /// ending with . public static string EndWith(this string @this, char character) => Modify(@this, () => string.Format(CultureInfo.InvariantCulture, "{0}{1}", @this.TrimEnd(character), character)); /// - /// Ensure that an input string ends with another string + /// Ensure that an input string ends with another string. /// - /// The input string - /// The string to end the string with + /// The input string. + /// The string to end the string with. + /// ending with . public static string EndWith(this string @this, string value) => Modify(@this, () => string.Format(CultureInfo.InvariantCulture, "{0}{1}", @this.TrimEnd(value), value)); } diff --git a/src/Jeebs/Extensions/StringExtensions.EscapeSingleQuotes.cs b/src/Jeebs/Extensions/StringExtensions.EscapeSingleQuotes.cs index e71b0b173..1eb2916b9 100644 --- a/src/Jeebs/Extensions/StringExtensions.EscapeSingleQuotes.cs +++ b/src/Jeebs/Extensions/StringExtensions.EscapeSingleQuotes.cs @@ -6,9 +6,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Escape all single quotes (when outputting text into a Javascript string) + /// Escape all single quotes (useful when outputting text into a Javascript string). /// - /// String to escape + /// String to escape. + /// with all single-quote characters escaped. public static string EscapeSingleQuotes(this string @this) => Modify(@this, () => @this.Replace("'", @"\'")); } diff --git a/src/Jeebs/Extensions/StringExtensions.GetAcronym.cs b/src/Jeebs/Extensions/StringExtensions.GetAcronym.cs index 9766fa9ae..5f4cd2fa1 100644 --- a/src/Jeebs/Extensions/StringExtensions.GetAcronym.cs +++ b/src/Jeebs/Extensions/StringExtensions.GetAcronym.cs @@ -8,9 +8,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Generate an acronym from a string + /// Generate an acronym from a string. /// - /// Input string + /// Input string. + /// Acronym. public static string GetAcronym(this string @this) { var acronym = new StringBuilder(); diff --git a/src/Jeebs/Extensions/StringExtensions.GetMimeFromExtension.cs b/src/Jeebs/Extensions/StringExtensions.GetMimeFromExtension.cs index 5d9b1e6a1..a7d90a408 100644 --- a/src/Jeebs/Extensions/StringExtensions.GetMimeFromExtension.cs +++ b/src/Jeebs/Extensions/StringExtensions.GetMimeFromExtension.cs @@ -6,9 +6,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Parse the Mime Type of a filename using its extension + /// Parse the Mime Type of a filename using its extension. /// - /// String object + /// String object. + /// Mime Type. public static string GetMimeFromExtension(this string @this) => Modify(@this, () => { diff --git a/src/Jeebs/Extensions/StringExtensions.HtmlDecode.cs b/src/Jeebs/Extensions/StringExtensions.HtmlDecode.cs index bbbe34eb4..a037587fd 100644 --- a/src/Jeebs/Extensions/StringExtensions.HtmlDecode.cs +++ b/src/Jeebs/Extensions/StringExtensions.HtmlDecode.cs @@ -6,9 +6,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Decode HTML entities + /// Decode HTML entities. /// - /// Input string + /// Input string. + /// HTML decoded string. public static string HtmlDecode(this string @this) => Modify(@this, () => System.Net.WebUtility.HtmlDecode(@this)); } diff --git a/src/Jeebs/Extensions/StringExtensions.HtmlEncode.cs b/src/Jeebs/Extensions/StringExtensions.HtmlEncode.cs index 96389b083..4fa356fd1 100644 --- a/src/Jeebs/Extensions/StringExtensions.HtmlEncode.cs +++ b/src/Jeebs/Extensions/StringExtensions.HtmlEncode.cs @@ -6,9 +6,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Encode HTML entities + /// Encode HTML entities. /// - /// Input string + /// Input string. + /// HTML encoded string. public static string HtmlEncode(this string @this) => Modify(@this, () => System.Net.WebUtility.HtmlEncode(@this)); } diff --git a/src/Jeebs/Extensions/StringExtensions.NoLongerThan.cs b/src/Jeebs/Extensions/StringExtensions.NoLongerThan.cs index 151820980..201da289f 100644 --- a/src/Jeebs/Extensions/StringExtensions.NoLongerThan.cs +++ b/src/Jeebs/Extensions/StringExtensions.NoLongerThan.cs @@ -5,14 +5,23 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { + /// + public static string NoLongerThan(this string @this, int maxLength) => + NoLongerThan(@this, maxLength, "..", string.Empty); + + /// + public static string NoLongerThan(this string @this, int maxLength, string continuation) => + NoLongerThan(@this, maxLength, continuation, string.Empty); + /// - /// Ensure a string is no longer than the specified maximum + /// Ensure a string is no longer than the specified maximum length. /// - /// Input string - /// The maximum length of the string - /// The continuation string to append to strings longer than the maximum - /// Text to return if the primary string is empty - public static string NoLongerThan(this string @this, int maxLength, string continuation, string? empty) => + /// Input string. + /// The maximum length of the string. + /// The continuation string to append to strings longer than the maximum. + /// Text to return if the primary string is empty. + /// String cut to with appended. + public static string NoLongerThan(this string @this, int maxLength, string continuation, string empty) => Modify(@this, () => (maxLength > 0 && @this.Length > maxLength) switch { @@ -24,12 +33,4 @@ public static string NoLongerThan(this string @this, int maxLength, string conti }, empty ); - - /// - public static string NoLongerThan(this string @this, int maxLength, string continuation) => - NoLongerThan(@this, maxLength, continuation, null); - - /// - public static string NoLongerThan(this string @this, int maxLength) => - NoLongerThan(@this, maxLength, "..", null); } diff --git a/src/Jeebs/Extensions/StringExtensions.Normalise.cs b/src/Jeebs/Extensions/StringExtensions.Normalise.cs index 8a7089946..754643767 100644 --- a/src/Jeebs/Extensions/StringExtensions.Normalise.cs +++ b/src/Jeebs/Extensions/StringExtensions.Normalise.cs @@ -8,22 +8,27 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Normalise a string by making it lowercase, stripping all non-letters and replacing spaces with - + /// Normalise a string by making it lowercase, stripping all non-letters and replacing spaces with '-'. /// - /// String to perform operation on + /// Input string. + /// Normalised string. public static string Normalise(this string @this) => Modify(@this, () => { // Make lowercase, and remove non-letters characters - var nonNormalisedCharacters = UnwantedCharactersRegex(); - var normalised = nonNormalisedCharacters.Replace(@this.ToLowerInvariant(), "").Trim(); + var normalised = UnwantedCharactersRegex() + .Replace(@this.ToLowerInvariant(), "") + .Trim(); - // Remove hyphens from the start of the string - normalised = normalised.TrimStart('-'); + // Trim hyphens from the start and end of the string + normalised = normalised + .Trim('-'); // Replace multiple spaces and hyphens with a single hyphen - var multipleSpacesAndHyphens = MultipleSpacesAndHyphensRegex(); - return multipleSpacesAndHyphens.Replace(normalised, "-"); + normalised = MultipleSpacesAndHyphensRegex() + .Replace(normalised, "-"); + + return normalised; }); [GeneratedRegex("[^a-z -]")] diff --git a/src/Jeebs/Extensions/StringExtensions.NullIfEmpty.cs b/src/Jeebs/Extensions/StringExtensions.NullIfEmpty.cs deleted file mode 100644 index b0ff1fb30..000000000 --- a/src/Jeebs/Extensions/StringExtensions.NullIfEmpty.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs.Extensions; - -public static partial class StringExtensions -{ - /// - /// Return null if the string is empty or null - otherwise, return the string - /// - /// String object - public static string NullIfEmpty(this string @this) => - Modify(@this, () => @this); -} diff --git a/src/Jeebs/Extensions/StringExtensions.Pluralise.cs b/src/Jeebs/Extensions/StringExtensions.Pluralise.cs index 94d2205fb..f6398b46c 100644 --- a/src/Jeebs/Extensions/StringExtensions.Pluralise.cs +++ b/src/Jeebs/Extensions/StringExtensions.Pluralise.cs @@ -10,10 +10,12 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Rules for converting singular words into plural words - /// This comes from https://mattgrande.wordpress.com/2009/10/28/pluralization-helper-for-c/ - /// and https://github.com/mattgrande/Grande.Pluralizer/blob/master/Grande.Pluralization/Pluralizer.cs + /// Rules for converting singular words into plural words. /// + /// + /// This comes from https://mattgrande.wordpress.com/2009/10/28/pluralization-helper-for-c/ + /// and https://github.com/mattgrande/Grande.Pluralizer/blob/master/Grande.Pluralization/Pluralizer.cs. + /// private static readonly IDictionary Pluralisations = new Dictionary { { "person", "people" }, @@ -23,14 +25,14 @@ public static partial class StringExtensions { "foot", "feet" }, { "tooth", "teeth" }, { "goose", "geese" }, - { "(.*[^af])fe?$", "$1ves" }, // ie, wolf, wife, but not giraffe, gaffe, safe + { "(.*[^af])fe?$", "$1ves" }, // e.g. wolf, wife, but not giraffe, gaffe, safe { "(hu|talis|otto|Ger|Ro)man$", "$1mans" }, // Exceptions for man -> men { "(.*)man$", "$1men" }, { "(.+[^aeiou])y$", "$1ies" }, { "(.+zz)$", "$1es" }, // Buzz -> Buzzes { "(.+z)$", "$1zes" }, // Quiz -> Quizzes { "([m|l])ouse$", "$1ice" }, - { "(append|matr|ind)(e|i)x$", "$1ices" }, // ie, Matrix, Index + { "(append|matr|ind)(e|i)x$", "$1ices" }, // e.g. Matrix, Index { "(octop|vir|radi|fung)us$", "$1i" }, { "(phyl|milleni|spectr)um$", "$1a" }, { "(cris|ax)is$", "$1es" }, @@ -40,10 +42,11 @@ public static partial class StringExtensions }; /// - /// 'Pluralise' a string + /// 'Pluralise' a string. /// - /// The string to pluralise - /// The number of items + /// Input string. + /// The number of items. + /// Pluralised string. public static string Pluralise(this string @this, long count) { if (count == 1) diff --git a/src/Jeebs/Extensions/StringExtensions.ReplaceAll.cs b/src/Jeebs/Extensions/StringExtensions.ReplaceAll.cs index e8874dc1a..3862f569f 100644 --- a/src/Jeebs/Extensions/StringExtensions.ReplaceAll.cs +++ b/src/Jeebs/Extensions/StringExtensions.ReplaceAll.cs @@ -6,11 +6,12 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Replace all strings in an array + /// Replace all strings in an array with a single value. /// - /// String to perform operation on - /// Array of strings to replace - /// String to replace occurrences with + /// Input string. + /// Array of strings to replace. + /// String to replace occurrences with. + /// with values replaced by . public static string ReplaceAll(this string @this, string[] replace, string with) => Modify(@this, () => { diff --git a/src/Jeebs/Extensions/StringExtensions.ReplaceHtmlTags.cs b/src/Jeebs/Extensions/StringExtensions.ReplaceHtmlTags.cs index 1ddf09e3d..0d92b653a 100644 --- a/src/Jeebs/Extensions/StringExtensions.ReplaceHtmlTags.cs +++ b/src/Jeebs/Extensions/StringExtensions.ReplaceHtmlTags.cs @@ -7,25 +7,18 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { + /// + public static string ReplaceHtmlTags(this string @this) => + ReplaceHtmlTags(@this, string.Empty); + /// - /// Replace all HTML tags + /// Replace all HTML tags. /// - /// The input string - /// String to replace HTML tags with - public static string ReplaceHtmlTags(this string @this, string? replaceWith) => - Modify(@this, () => - { - // Make sure replaceWith isn't null - replaceWith ??= string.Empty; - - // Now replace all HTML characters - var re = HtmlCharactersRegex(); - return re.Replace(@this, replaceWith); - }); - - /// - public static string ReplaceHtmlTags(this string @this) => - ReplaceHtmlTags(@this, null); + /// Input string. + /// String to replace HTML tags with. + /// with HTML tags replaced by . + public static string ReplaceHtmlTags(this string @this, string with) => + Modify(@this, () => HtmlCharactersRegex().Replace(@this, with ?? string.Empty)); [GeneratedRegex("<.*?>")] private static partial Regex HtmlCharactersRegex(); diff --git a/src/Jeebs/Extensions/StringExtensions.ReplaceNonLetter.cs b/src/Jeebs/Extensions/StringExtensions.ReplaceNonLetter.cs new file mode 100644 index 000000000..bd422bc28 --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.ReplaceNonLetter.cs @@ -0,0 +1,25 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Text.RegularExpressions; + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + public static string ReplaceNonLetter(this string @this) => + ReplaceNonWord(@this, string.Empty); + + /// + /// Replace non-letter characters in a string. + /// + /// String to perform operation on. + /// String to replace unwanted characters with. + /// with non-word characters replaced by . + public static string ReplaceNonLetter(this string @this, string with) => + Modify(@this, () => NonLetterCharactersRegex().Replace(@this, with ?? string.Empty)); + + [GeneratedRegex("[^a-zA-Z]+")] + private static partial Regex NonLetterCharactersRegex(); +} diff --git a/src/Jeebs/Extensions/StringExtensions.ReplaceNonNumerical.cs b/src/Jeebs/Extensions/StringExtensions.ReplaceNonNumerical.cs index d3f659561..151e8286c 100644 --- a/src/Jeebs/Extensions/StringExtensions.ReplaceNonNumerical.cs +++ b/src/Jeebs/Extensions/StringExtensions.ReplaceNonNumerical.cs @@ -7,28 +7,18 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { - /// - /// Ensure a string contains only numbers - /// - /// The input string - /// String to replace non-numerical characters with - public static string ReplaceNonNumerical(this string @this, string? replaceWith) => - Modify(@this, () => - { - // Make sure replaceWith isn't null - if (replaceWith is null) - { - replaceWith = string.Empty; - } - - // Now replace all non-numerical characters - var nonNumerical = NonNumericalCharactersRegex(); - return nonNumerical.Replace(@this, replaceWith); - }); - /// public static string ReplaceNonNumerical(this string @this) => - ReplaceNonNumerical(@this, null); + ReplaceNonNumerical(@this, string.Empty); + + /// + /// Ensure a string contains only numbers. + /// + /// Input string. + /// String to replace non-numerical characters with. + /// with non-numerical characters replaced by . + public static string ReplaceNonNumerical(this string @this, string with) => + Modify(@this, () => NonNumericalCharactersRegex().Replace(@this, with ?? string.Empty)); [GeneratedRegex("[^0-9]+")] private static partial Regex NonNumericalCharactersRegex(); diff --git a/src/Jeebs/Extensions/StringExtensions.ReplaceNonWord.cs b/src/Jeebs/Extensions/StringExtensions.ReplaceNonWord.cs index 5d18321f7..4a7479149 100644 --- a/src/Jeebs/Extensions/StringExtensions.ReplaceNonWord.cs +++ b/src/Jeebs/Extensions/StringExtensions.ReplaceNonWord.cs @@ -7,28 +7,18 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { - /// - /// Replace non-word characters in a string, useful for creating HTML IDs (for example) - /// - /// String to perform operation on - /// String to replace unwanted characters with - public static string ReplaceNonWord(this string @this, string? replaceWith) => - Modify(@this, () => - { - // Make sure replaceWith isn't null - if (replaceWith is null) - { - replaceWith = string.Empty; - } - - // Now replace all non-word characters - var nonWord = NonWordCharactersRegex(); - return nonWord.Replace(@this, replaceWith); - }); - /// public static string ReplaceNonWord(this string @this) => - ReplaceNonWord(@this, null); + ReplaceNonWord(@this, string.Empty); + + /// + /// Replace non-word characters in a string, useful for creating HTML IDs (for example). + /// + /// String to perform operation on. + /// String to replace unwanted characters with. + /// with non-word characters replaced by . + public static string ReplaceNonWord(this string @this, string with) => + Modify(@this, () => NonWordCharactersRegex().Replace(@this, with ?? string.Empty)); [GeneratedRegex("\\W+")] private static partial Regex NonWordCharactersRegex(); diff --git a/src/Jeebs/Extensions/StringExtensions.Singularise.cs b/src/Jeebs/Extensions/StringExtensions.Singularise.cs index e155b4c86..e5cf1f642 100644 --- a/src/Jeebs/Extensions/StringExtensions.Singularise.cs +++ b/src/Jeebs/Extensions/StringExtensions.Singularise.cs @@ -10,9 +10,11 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Rules for converting plural words into singular words - /// This comes from http://lotsacode.wordpress.com/2010/03/05/singularization-pluralization-in-c/ + /// Rules for converting plural words into singular words. /// + /// + /// This comes from http://lotsacode.wordpress.com/2010/03/05/singularization-pluralization-in-c/ + /// private static readonly IDictionary Singularisations = new Dictionary { { "people", "person" }, @@ -39,9 +41,10 @@ public static partial class StringExtensions }; /// - /// 'Singularise' a string + /// 'Singularise' a string. /// - /// The string to singularise + /// Input string. + /// Singularised string. public static string Singularise(this string @this) { if (UnPluralisables.All.Contains(@this.ToLowerInvariant())) diff --git a/src/Jeebs/Extensions/StringExtensions.SplitByCapitals.cs b/src/Jeebs/Extensions/StringExtensions.SplitByCapitals.cs index 9715875cf..58f9e8fdd 100644 --- a/src/Jeebs/Extensions/StringExtensions.SplitByCapitals.cs +++ b/src/Jeebs/Extensions/StringExtensions.SplitByCapitals.cs @@ -8,15 +8,12 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Split a CamelCase string by capitals + /// Split a CamelCase string by capital letters. /// - /// String object + /// Input string. + /// split by capital letters. public static string SplitByCapitals(this string @this) => - Modify(@this, () => - { - var capitals = CapitalLettersRegex(); - return capitals.Replace(@this, " $2").Trim(); - }); + Modify(@this, () => CapitalLettersRegex().Replace(@this, " $2").Trim()); [GeneratedRegex("( *)([A-Z])")] private static partial Regex CapitalLettersRegex(); diff --git a/src/Jeebs/Extensions/StringExtensions.StartWith.cs b/src/Jeebs/Extensions/StringExtensions.StartWith.cs index 438d4ec8a..350fd9d0b 100644 --- a/src/Jeebs/Extensions/StringExtensions.StartWith.cs +++ b/src/Jeebs/Extensions/StringExtensions.StartWith.cs @@ -8,10 +8,20 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Ensure that an input string starts with a single defined character + /// Ensure that an input string starts with a single defined character. /// - /// The input string - /// The character to start the string with + /// The input string. + /// The character to start the string with. + /// starting with . public static string StartWith(this string @this, char character) => Modify(@this, () => string.Format(CultureInfo.InvariantCulture, "{0}{1}", character, @this.TrimStart(character))); + + /// + /// Ensure that an input string starts with another string. + /// + /// The input string. + /// The string to start the string with. + /// starting with . + public static string StartWith(this string @this, string value) => + Modify(@this, () => string.Format(CultureInfo.InvariantCulture, "{0}{1}", value, @this.TrimStart(value))); } diff --git a/src/Jeebs/Extensions/StringExtensions.ToASCII.cs b/src/Jeebs/Extensions/StringExtensions.ToASCII.cs index 6a94e0330..23d650778 100644 --- a/src/Jeebs/Extensions/StringExtensions.ToASCII.cs +++ b/src/Jeebs/Extensions/StringExtensions.ToASCII.cs @@ -9,10 +9,13 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Return the input string encoded into ASCII Html Entities - /// Warning: this only works with ASCII 'Printable' characters (32->126), NOT 'Extended' characters + /// Return the input string encoded into ASCII Html Entities. /// - /// The input string + /// + /// Warning: this only works with ASCII 'Printable' characters (32->126), NOT 'Extended' characters. + /// + /// Input string. + /// ASCII-encoded string. public static string ToASCII(this string @this) => Modify(@this, () => { diff --git a/src/Jeebs/Extensions/StringExtensions.ToCamelCase.cs b/src/Jeebs/Extensions/StringExtensions.ToCamelCase.cs new file mode 100644 index 000000000..536029b91 --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.ToCamelCase.cs @@ -0,0 +1,21 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + /// Converts a string to camel case. + /// + /// + /// Camel Case = numberOfDoughnuts + /// + /// + /// + /// + /// Input string. + /// in camelCase. + public static string ToCamelCase(this string @this) => + Modify(@this, () => @this.ToTitleCase().ReplaceNonLetter().ToLowerFirst()); +} diff --git a/src/Jeebs/Extensions/StringExtensions.ToKebabCase.cs b/src/Jeebs/Extensions/StringExtensions.ToKebabCase.cs new file mode 100644 index 000000000..ab6ad8288 --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.ToKebabCase.cs @@ -0,0 +1,21 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + /// Converts a string to kebab case. + /// + /// + /// Kebab Case = number-of-doughnuts + /// + /// + /// + /// + /// Input string. + /// in kebab-case. + public static string ToKebabCase(this string @this) => + Modify(@this, () => @this.ReplaceNonLetter("-").ToLowerInvariant()); +} diff --git a/src/Jeebs/Extensions/StringExtensions.ToLowerFirst.cs b/src/Jeebs/Extensions/StringExtensions.ToLowerFirst.cs index c7b128614..bb76910f7 100644 --- a/src/Jeebs/Extensions/StringExtensions.ToLowerFirst.cs +++ b/src/Jeebs/Extensions/StringExtensions.ToLowerFirst.cs @@ -1,20 +1,15 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System.Globalization; - namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Equivalent of PHP lcfirst() - makes the first character of a string lowercase + /// Equivalent of PHP lcfirst() - makes the first character of a string lowercase. /// - /// String object + /// Input string. + /// with first character in lower case. public static string ToLowerFirst(this string @this) => - Modify(@this, () => char.ToLower(@this[0], CultureInfo.InvariantCulture) + @this[1..]); - - /// - public static string ToCamelCase(this string @this) => - ToLowerFirst(@this); + Modify(@this, () => char.ToLowerInvariant(@this[0]) + @this[1..]); } diff --git a/src/Jeebs/Extensions/StringExtensions.ToPascalCase.cs b/src/Jeebs/Extensions/StringExtensions.ToPascalCase.cs new file mode 100644 index 000000000..ade9005fc --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.ToPascalCase.cs @@ -0,0 +1,21 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + /// Converts a string to pascal case. + /// + /// + /// Pascal Case = NumberOfDoughnuts + /// + /// + /// + /// + /// Input string. + /// in PascalCase. + public static string ToPascalCase(this string @this) => + Modify(@this, () => @this.ToTitleCase().ReplaceNonLetter()); +} diff --git a/src/Jeebs/Extensions/StringExtensions.ToSentenceCase.cs b/src/Jeebs/Extensions/StringExtensions.ToSentenceCase.cs index 05f8f30e4..8941e246b 100644 --- a/src/Jeebs/Extensions/StringExtensions.ToSentenceCase.cs +++ b/src/Jeebs/Extensions/StringExtensions.ToSentenceCase.cs @@ -1,16 +1,15 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System.Globalization; - namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Equivalent of PHP ucfirst() - except it lowers the case of all subsequent letters as well + /// Equivalent of PHP ucfirst() - except it lowers the case of all subsequent letters as well. /// - /// String object + /// Input string. + /// with first character in upper case and all others in lower case. public static string ToSentenceCase(this string @this) => - Modify(@this, () => char.ToUpper(@this[0], CultureInfo.InvariantCulture) + @this[1..].ToLowerInvariant()); + Modify(@this, () => char.ToUpperInvariant(@this[0]) + @this[1..].ToLowerInvariant()); } diff --git a/src/Jeebs/Extensions/StringExtensions.ToSnakeCase.cs b/src/Jeebs/Extensions/StringExtensions.ToSnakeCase.cs new file mode 100644 index 000000000..9e8ff6e89 --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.ToSnakeCase.cs @@ -0,0 +1,21 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + /// Converts a string to snake case. + /// + /// + /// Snake Case = number_of_doughnuts + /// + /// + /// + /// + /// Input string. + /// in snake_case. + public static string ToSnakeCase(this string @this) => + Modify(@this, () => @this.ReplaceNonLetter("_").ToLowerInvariant()); +} diff --git a/src/Jeebs/Extensions/StringExtensions.ToTitleCase.cs b/src/Jeebs/Extensions/StringExtensions.ToTitleCase.cs index 56cbe5383..c452e0b85 100644 --- a/src/Jeebs/Extensions/StringExtensions.ToTitleCase.cs +++ b/src/Jeebs/Extensions/StringExtensions.ToTitleCase.cs @@ -8,9 +8,10 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Converts a string to Title Case (ignoring acronyms) + /// Converts a string to Title Case (ignoring acronyms). /// - /// String object + /// Input string. + /// public static string ToTitleCase(this string @this) => Modify(@this, () => { diff --git a/src/Jeebs/Extensions/StringExtensions.ToUpperFirst.cs b/src/Jeebs/Extensions/StringExtensions.ToUpperFirst.cs index 9952cdb4a..29e9503ac 100644 --- a/src/Jeebs/Extensions/StringExtensions.ToUpperFirst.cs +++ b/src/Jeebs/Extensions/StringExtensions.ToUpperFirst.cs @@ -1,20 +1,15 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System.Globalization; - namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Equivalent of PHP ucfirst() - makes the first character of a string uppercase + /// Equivalent of PHP ucfirst() - makes the first character of a string uppercase. /// - /// String object + /// Input string. + /// with first character in upper case. public static string ToUpperFirst(this string @this) => - Modify(@this, () => char.ToUpper(@this[0], CultureInfo.InvariantCulture) + @this[1..]); - - /// - public static string ToPascalCase(this string @this) => - ToUpperFirst(@this); + Modify(@this, () => char.ToUpperInvariant(@this[0]) + @this[1..]); } diff --git a/src/Jeebs/Extensions/StringExtensions.TrimEnd.cs b/src/Jeebs/Extensions/StringExtensions.TrimEnd.cs index f898d98ff..a8f12b886 100644 --- a/src/Jeebs/Extensions/StringExtensions.TrimEnd.cs +++ b/src/Jeebs/Extensions/StringExtensions.TrimEnd.cs @@ -8,10 +8,11 @@ namespace Jeebs.Extensions; public static partial class StringExtensions { /// - /// Trim a string from the end of another string + /// Trim a string from the end of another string. /// - /// String object - /// Value to trim + /// Input string. + /// Value to trim. + /// with trimmed from the end. public static string TrimEnd(this string @this, string value) => @this.EndsWith(value, StringComparison.InvariantCulture) switch { diff --git a/src/Jeebs/Extensions/StringExtensions.TrimStart.cs b/src/Jeebs/Extensions/StringExtensions.TrimStart.cs new file mode 100644 index 000000000..89798a6a4 --- /dev/null +++ b/src/Jeebs/Extensions/StringExtensions.TrimStart.cs @@ -0,0 +1,25 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs.Extensions; + +public static partial class StringExtensions +{ + /// + /// Trim a string from the start of another string. + /// + /// Input string. + /// Value to trim. + /// with trimmed from the start. + public static string TrimStart(this string @this, string value) => + @this.StartsWith(value, StringComparison.InvariantCulture) switch + { + true => + @this.Remove(@this.IndexOf(value, StringComparison.InvariantCulture)), + + false => + @this + }; +} diff --git a/src/Jeebs/Extensions/StringExtensions.cs b/src/Jeebs/Extensions/StringExtensions.cs index c1106db32..bcccbb0ad 100644 --- a/src/Jeebs/Extensions/StringExtensions.cs +++ b/src/Jeebs/Extensions/StringExtensions.cs @@ -6,23 +6,28 @@ namespace Jeebs.Extensions; /// -/// String Extensions +/// Extension methods for objects. /// public static partial class StringExtensions { + /// + private static string Modify(string s, Func perform) => + Modify(s, perform, string.Empty); + /// - /// Return empty if the input string is null or empty + /// Perform a modification on an input string. /// - /// Input string - /// Function to modify and return the input string - /// [Optional] String to return if @this is empty - private static string Modify(string @this, Func perform, string? empty = null) - { - if (string.IsNullOrEmpty(@this)) + /// Input string. + /// Function to modify and return the input string. + /// String to return if is empty. + /// Modified string (or if is null or empty). + private static string Modify(string s, Func perform, string empty) => + string.IsNullOrEmpty(s) switch { - return empty ?? @this; - } + false => + perform() ?? empty, - return perform(); - } + true => + empty + }; } diff --git a/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs b/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs index 0d2b16dde..5147e1ccf 100644 --- a/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs +++ b/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs @@ -19,9 +19,9 @@ internal sealed class DateTimeJsonConverter : JsonConverter /// Type /// JsonSerializerOptions public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => - F.ParseDateTime(reader.GetString()).Switch( + M.ParseDateTime(reader.GetString()).Match( some: x => new DateTime(x.Ticks, DateTimeKind.Utc), - none: _ => DateTime.MinValue.ToUniversalTime() + none: DateTime.MinValue.ToUniversalTime ); /// diff --git a/src/Jeebs/Functions/ListF.cs b/src/Jeebs/Functions/ListF.cs new file mode 100644 index 000000000..ba1487968 --- /dev/null +++ b/src/Jeebs/Functions/ListF.cs @@ -0,0 +1,64 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Collections.Generic; +using System.Linq; +using Jeebs.Collections; + +namespace Jeebs.Functions; + +/// +/// Alternative methods for creating and manipulating objects. +/// +public static class ListF +{ + /// + /// Create an empty . + /// + /// List Item type. + public static ImmutableList Empty() => + new(); + + /// + /// Create a new with the specified . + /// + /// List Item type. + /// Collection of items to add. + public static ImmutableList Create(IEnumerable items) => + new(items); + + /// + /// Create a new with the specified . + /// + /// List Item type. + /// Items to add. + public static ImmutableList Create(params T[]? args) => + args switch + { + T[] => + new(args), + + _ => + new() + }; + + /// + /// Deserialise a JSON list into an ImmutableList. + /// + /// List Item type. + /// JSON list. + public static ImmutableList Deserialise(string json) => + JsonF.Deserialise>(json) + .Match( + ok: x => Create(items: x), + fail: _ => new() + ); + + /// + /// Merge multiple objects into one. + /// + /// List Item type. + /// Lists to merge. + public static ImmutableList Merge(params IImmutableList[] lists) => + new(lists.SelectMany(x => x)); +} diff --git a/src/Jeebs/LogLevelExtensions.cs b/src/Jeebs/LogLevelExtensions.cs index 9228100ec..768c9f142 100644 --- a/src/Jeebs/LogLevelExtensions.cs +++ b/src/Jeebs/LogLevelExtensions.cs @@ -6,6 +6,9 @@ namespace Jeebs; +/// +/// Extension methods for objects. +/// public static class LogLevelExtensions { /// diff --git a/src/Jeebs/Reflection/LinqExpressionExtensions.cs b/src/Jeebs/Reflection/LinqExpressionExtensions.cs index 67b251244..5743162bc 100644 --- a/src/Jeebs/Reflection/LinqExpressionExtensions.cs +++ b/src/Jeebs/Reflection/LinqExpressionExtensions.cs @@ -4,12 +4,11 @@ using System; using System.Linq.Expressions; using System.Reflection; -using Jeebs.Messages; namespace Jeebs.Reflection; /// -/// LinqExpression Extensions: GetPropertyInfo +/// Extension methods for objects. /// public static class LinqExpressionExtensions { @@ -29,10 +28,10 @@ this Expression> @this x => typeof(TObject).HasProperty(x.Name) switch { true => - F.Some(new PropertyInfo((PropertyInfo)x)), + M.Wrap(new PropertyInfo((PropertyInfo)x)), false => - F.None>(new M.PropertyDoesNotExistOnTypeMsg(x.Name)) + M.None } ); @@ -53,18 +52,6 @@ private static Maybe GetMemberInfo(Expression expression) => memberExpression.Member, _ => - F.None() + M.None }; - - /// Messages - public static class M - { - /// Only MemberExpressions can be used for PropertyInfo purposes - public sealed record class ExpressionIsNotAMemberExpressionMsg : Msg; - - /// The specified property does not exist on the type - /// Type - /// Property Name - public sealed record class PropertyDoesNotExistOnTypeMsg(string Value) : WithValueMsg; - } } diff --git a/src/Jeebs/Reflection/ObjectExtensions.cs b/src/Jeebs/Reflection/ObjectExtensions.cs index eb487cf99..b36bf4818 100644 --- a/src/Jeebs/Reflection/ObjectExtensions.cs +++ b/src/Jeebs/Reflection/ObjectExtensions.cs @@ -4,19 +4,18 @@ using System; using System.Linq; using System.Reflection; -using Jeebs.Messages; namespace Jeebs.Reflection; /// -/// Object Extensions +/// Extension methods for objects (!). /// public static class ObjectExtensions { /// - /// Get array of object properties + /// Get array of object properties. /// - /// Object + /// Object. public static PropertyInfo[] GetProperties(this object @this) => @this switch { @@ -28,27 +27,27 @@ public static PropertyInfo[] GetProperties(this object @this) => }; /// - /// Return whether or not the object contains the specified property + /// Return whether or not the object contains the specified property. /// - /// Object - /// The name of the property whose value you want to return + /// Object. + /// The name of the property whose value you want to return. public static bool HasProperty(this object @this, string propertyName) => GetProperties(@this).Any(x => x.Name == propertyName); /// - /// Return the value of a property dynamically - i.e. by property name + /// Return the value of a property dynamically - i.e. by property name. /// - /// Object - /// The name of the property whose value you want to return + /// Object. + /// The name of the property whose value you want to return. public static Maybe GetPropertyValue(this object @this, string propertyName) => GetPropertyValue(@this, propertyName); /// - /// Return the value of a property dynamically - i.e. by property name + /// Return the value of a property dynamically - i.e. by property name. /// - /// Property type - /// Object - /// The name of the property whose value you want to return + /// Property type. + /// Object. + /// The name of the property whose value you want to return. public static Maybe GetPropertyValue(this object @this, string propertyName) { // Get type @@ -60,7 +59,7 @@ public static Maybe GetPropertyValue(this object @this, string propertyNam // If the types don't match, return None if (typeof(T) != typeof(object) && typeof(T) != info.PropertyType) { - return F.None(new M.UnexpectedPropertyTypeMsg((type, propertyName))); + return M.None; } // Get the value - if it's null return None @@ -70,32 +69,11 @@ public static Maybe GetPropertyValue(this object @this, string propertyNam val, _ => - F.None(new M.NullValueMsg((type, propertyName))) + M.None }; } // No property with this name was found - return F.None(new M.PropertyNotFoundMsg((type, propertyName))); - } - - /// Messages - public static class M - { - /// See and - /// Object type and Property name - public abstract record class GetPropertyMsg((Type type, string property) Value) : WithValueMsg<(Type type, string property)>(); - - /// The property could not be found - /// - public sealed record class PropertyNotFoundMsg((Type, string) Value) : GetPropertyMsg(Value); - - /// The property value is null - /// - public sealed record class NullValueMsg((Type, string) Value) : GetPropertyMsg(Value); - - /// The property type doesn't match the requested type - /// Requested property value type - /// - public sealed record class UnexpectedPropertyTypeMsg((Type type, string property) Value) : GetPropertyMsg(Value); + return M.None; } } diff --git a/src/Jeebs/Reflection/PropertyInfoExtensions.cs b/src/Jeebs/Reflection/PropertyInfoExtensions.cs index 3d31e760e..a3935f181 100644 --- a/src/Jeebs/Reflection/PropertyInfoExtensions.cs +++ b/src/Jeebs/Reflection/PropertyInfoExtensions.cs @@ -8,14 +8,14 @@ namespace Jeebs.Reflection; /// -/// PropertyInfo Extensions +/// Extension methods for objects. /// public static class PropertyInfoExtensions { /// - /// Returns true if the property has been marked as nullable using the C# 8+ nullable feature + /// Returns true if the property has been marked as nullable using the C# 8+ nullable feature. /// - /// PropertyInfo + /// PropertyInfo. public static bool IsNullable(this PropertyInfo @this) => (@this.PropertyType.GenericTypeArguments.Length == 1 && @this.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) || @this.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute"); diff --git a/src/Jeebs/ResultExtensions.cs b/src/Jeebs/ResultExtensions.cs index 91abfd12a..598221e5b 100644 --- a/src/Jeebs/ResultExtensions.cs +++ b/src/Jeebs/ResultExtensions.cs @@ -4,6 +4,6 @@ namespace Jeebs; /// -/// extension methods. +/// Extension methods for object. /// public static partial class ResultExtensions { } diff --git a/src/Jeebs/TypeExtensions.cs b/src/Jeebs/TypeExtensions.cs index 19307a3f0..36c7374e6 100644 --- a/src/Jeebs/TypeExtensions.cs +++ b/src/Jeebs/TypeExtensions.cs @@ -7,7 +7,7 @@ namespace Jeebs; /// -/// Type extension methods +/// Extension methods for objects. /// public static class TypeExtensions { From 58f272620678064a923690f61b2a537da71df2c7 Mon Sep 17 00:00:00 2001 From: bfren Date: Wed, 27 Mar 2024 13:38:21 +0000 Subject: [PATCH 033/202] Using array initialisers --- apps/AppConsole/Messages.cs | 2 +- src/Jeebs.Data.Query/QueryBuilderWithFrom.cs | 2 +- .../Functions/MapF.GetColumnWithAttribute.cs | 4 +-- .../Map/Functions/MapF.GetIdColumn.cs | 4 +-- src/Jeebs.Data/Query/FluentQuery.Execute.cs | 2 +- src/Jeebs.Data/Repository.cs | 6 ++-- src/Jeebs.WordPress/Enums/PostType.cs | 2 +- src/Jeebs.WordPress/Enums/Taxonomy.cs | 2 +- .../_/MySqlDbClient/GetQuery_Tests.cs | 32 ++++++++--------- .../_/PostgreSqlDbClient/GetQuery_Tests.cs | 32 ++++++++--------- .../_/SqlServerDbClient/GetQuery_Tests.cs | 32 ++++++++--------- .../_/SqliteDbClient/GetQuery_Tests.cs | 32 ++++++++--------- .../FluentQueryHelper/AssertWhereIn_Tests.cs | 6 ++-- .../AssertWhereNotIn_Tests.cs | 6 ++-- .../QueryF/GetColumnsFromList_Tests.cs | 2 +- .../QueryF/GetSelectFromList_Tests.cs | 2 +- .../QueryF/GetWhereAndParameters_Tests.cs | 36 +++++++++---------- .../Query/_/FluentQuery/WhereIn_Tests.cs | 2 +- .../Query/_/FluentQuery/WhereNotIn_Tests.cs | 2 +- .../GetClaim_Tests.cs | 6 ++-- .../GetUserId_Tests.cs | 8 ++--- .../HasClaim_Tests.cs | 6 ++-- .../IsSuper_Tests.cs | 6 ++-- .../_/ClaimsPrincipalExtensions/_Setup.cs | 2 +- .../Models/Menu/MenuF/GetUris_Tests.cs | 4 +-- .../ImmutableList/GetEnumerator_Tests.cs | 2 +- .../ImmutableList/Indexer_Tests.cs | 6 ++-- .../ImmutableList/WithRange_Tests.cs | 4 +-- .../ImmutableList/WithoutRange_Tests.cs | 4 +-- tests/Tests.Jeebs/Logging/Log/Msg_Tests.cs | 2 +- 30 files changed, 129 insertions(+), 129 deletions(-) diff --git a/apps/AppConsole/Messages.cs b/apps/AppConsole/Messages.cs index 4fb851fcb..9da85536f 100644 --- a/apps/AppConsole/Messages.cs +++ b/apps/AppConsole/Messages.cs @@ -16,7 +16,7 @@ public record FormattedMsg : Msg "Values {One} and {Two}"; public override object[]? Args => - new object[] { Rnd.Int, Rnd.Guid }; + [Rnd.Int, Rnd.Guid]; } public record WithValue(string Value) : WithValueMsg; diff --git a/src/Jeebs.Data.Query/QueryBuilderWithFrom.cs b/src/Jeebs.Data.Query/QueryBuilderWithFrom.cs index 674a10172..7f88aa277 100644 --- a/src/Jeebs.Data.Query/QueryBuilderWithFrom.cs +++ b/src/Jeebs.Data.Query/QueryBuilderWithFrom.cs @@ -32,7 +32,7 @@ public sealed record class QueryBuilderWithFrom : IQueryBuilderWithFrom internal QueryBuilderWithFrom(ITable from) { Parts = new QueryParts(from); - Tables = new(new[] { from }); + Tables = new([from]); } /// diff --git a/src/Jeebs.Data/Map/Functions/MapF.GetColumnWithAttribute.cs b/src/Jeebs.Data/Map/Functions/MapF.GetColumnWithAttribute.cs index 97c0c2184..db68db195 100644 --- a/src/Jeebs.Data/Map/Functions/MapF.GetColumnWithAttribute.cs +++ b/src/Jeebs.Data/Map/Functions/MapF.GetColumnWithAttribute.cs @@ -57,7 +57,7 @@ public sealed record class NoPropertyWithAttributeMsg() : Ms /// public override object[]? Args => - new object[] { typeof(TAttribute), typeof(TTable) }; + [typeof(TAttribute), typeof(TTable)]; } /// Too many properties with specified attribute found on table @@ -71,7 +71,7 @@ public sealed record class TooManyPropertiesWithAttributeMsg /// public override object[]? Args => - new object[] { typeof(TAttribute), typeof(TTable) }; + [typeof(TAttribute), typeof(TTable)]; } } } diff --git a/src/Jeebs.Data/Map/Functions/MapF.GetIdColumn.cs b/src/Jeebs.Data/Map/Functions/MapF.GetIdColumn.cs index 3856ceb4c..8969bbcf6 100644 --- a/src/Jeebs.Data/Map/Functions/MapF.GetIdColumn.cs +++ b/src/Jeebs.Data/Map/Functions/MapF.GetIdColumn.cs @@ -54,7 +54,7 @@ public sealed record class NoIdPropertyMsg() : Msg /// public override object[]? Args => - new object[] { nameof(IWithId.Id), typeof(IdAttribute), typeof(TTable) }; + [nameof(IWithId.Id), typeof(IdAttribute), typeof(TTable)]; } /// Too many properties with specified attribute found on table @@ -67,7 +67,7 @@ public sealed record class TooManyPropertiesWithIdAttributeMsg() : Msg /// public override object[]? Args => - new object[] { typeof(IdAttribute), typeof(TTable) }; + [typeof(IdAttribute), typeof(TTable)]; } } } diff --git a/src/Jeebs.Data/Query/FluentQuery.Execute.cs b/src/Jeebs.Data/Query/FluentQuery.Execute.cs index 22c4e4ec6..a2f3ed9da 100644 --- a/src/Jeebs.Data/Query/FluentQuery.Execute.cs +++ b/src/Jeebs.Data/Query/FluentQuery.Execute.cs @@ -26,7 +26,7 @@ public Task> ExecuteAsync(string columnAlias, IDbTransacti .BindAsync(x => Update(parts => parts with { - SelectColumns = new ColumnList(new[] { x }) + SelectColumns = new ColumnList([x]) }) .QuerySingleAsync(transaction) ); diff --git a/src/Jeebs.Data/Repository.cs b/src/Jeebs.Data/Repository.cs index 33ee09420..41e3f2235 100644 --- a/src/Jeebs.Data/Repository.cs +++ b/src/Jeebs.Data/Repository.cs @@ -51,11 +51,11 @@ internal virtual void WriteToLog(string message, object[] args) => /// /// Operation (method) name protected void LogFunc(string operation) => - WriteToLog("{Operation} {Entity}", new object[] - { + WriteToLog("{Operation} {Entity}", + [ operation.Replace("Async", string.Empty), typeof(TEntity).Name.Replace("Entity", string.Empty) - }); + ]); #region Fluent Queries diff --git a/src/Jeebs.WordPress/Enums/PostType.cs b/src/Jeebs.WordPress/Enums/PostType.cs index b029ff2d1..3e2d628df 100644 --- a/src/Jeebs.WordPress/Enums/PostType.cs +++ b/src/Jeebs.WordPress/Enums/PostType.cs @@ -64,7 +64,7 @@ internal static HashSet AllTest() => /// Populate set of post types /// static PostType() => - All = new HashSet(new[] { Post, Page, Revision, Attachment, MenuItem, AdvancedCustomField }); + All = new HashSet([Post, Page, Revision, Attachment, MenuItem, AdvancedCustomField]); /// /// Add a custom post type diff --git a/src/Jeebs.WordPress/Enums/Taxonomy.cs b/src/Jeebs.WordPress/Enums/Taxonomy.cs index 1d9a00607..6a1237369 100644 --- a/src/Jeebs.WordPress/Enums/Taxonomy.cs +++ b/src/Jeebs.WordPress/Enums/Taxonomy.cs @@ -59,7 +59,7 @@ internal static HashSet AllTest() => /// Populate list of taxonomies /// static Taxonomy() => - All = new HashSet(new[] { PostCategory, PostTag, LinkCategory, NavMenu }); + All = new HashSet([PostCategory, PostTag, LinkCategory, NavMenu]); /// /// Add a custom taxonomy diff --git a/tests/Tests.Jeebs.Data.Clients.MySql/_/MySqlDbClient/GetQuery_Tests.cs b/tests/Tests.Jeebs.Data.Clients.MySql/_/MySqlDbClient/GetQuery_Tests.cs index e8d36ad4d..98bf0a208 100644 --- a/tests/Tests.Jeebs.Data.Clients.MySql/_/MySqlDbClient/GetQuery_Tests.cs +++ b/tests/Tests.Jeebs.Data.Clients.MySql/_/MySqlDbClient/GetQuery_Tests.cs @@ -36,11 +36,11 @@ public void With_Predicates_Returns_Valid_Select_Query() var p1Operator = Compare.MoreThanOrEqual; var p1Value = Rnd.Int; - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ ( p0Column, p0Operator, p0Value ), ( p1Column, p1Operator, p1Value ) - }); + ]); var client = new MySqlDbClient(); @@ -158,7 +158,7 @@ private static void Test_Joins(Func FluentQueryHelper.AssertWhereIn(c, x => x.Bar, new[] { Rnd.Lng, Rnd.Lng }); + var action = (ICall c) => FluentQueryHelper.AssertWhereIn(c, x => x.Bar, [Rnd.Lng, Rnd.Lng]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); @@ -46,7 +46,7 @@ public void Incorrect_Generic_Argument__Throws_GenericArgumentException() fluent.WhereIn(x => x.Foo, values); // Act - var action = (ICall c) => FluentQueryHelper.AssertWhereIn(c, x => x.Bar, new[] { Rnd.Lng, Rnd.Lng }); + var action = (ICall c) => FluentQueryHelper.AssertWhereIn(c, x => x.Bar, [Rnd.Lng, Rnd.Lng]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); @@ -61,7 +61,7 @@ public void Values_Not_Equal__Throws_EqualTypeException() fluent.WhereIn(x => x.Foo, values); // Act - var action = (ICall c) => FluentQueryHelper.AssertWhereIn(c, x => x.Foo, new[] { Rnd.Str, Rnd.Str }); + var action = (ICall c) => FluentQueryHelper.AssertWhereIn(c, x => x.Foo, [Rnd.Str, Rnd.Str]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); diff --git a/tests/Tests.Jeebs.Data.Testing/Query/FluentQueryHelper/AssertWhereNotIn_Tests.cs b/tests/Tests.Jeebs.Data.Testing/Query/FluentQueryHelper/AssertWhereNotIn_Tests.cs index 2b9ea321b..b62ba21de 100644 --- a/tests/Tests.Jeebs.Data.Testing/Query/FluentQueryHelper/AssertWhereNotIn_Tests.cs +++ b/tests/Tests.Jeebs.Data.Testing/Query/FluentQueryHelper/AssertWhereNotIn_Tests.cs @@ -31,7 +31,7 @@ public void Incorrect_Method__Throws_MethodNameException() fluent.Maximum(Rnd.ULng); // Act - var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Bar, new[] { Rnd.Lng, Rnd.Lng }); + var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Bar, [Rnd.Lng, Rnd.Lng]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); @@ -46,7 +46,7 @@ public void Incorrect_Generic_Argument__Throws_GenericArgumentException() fluent.WhereNotIn(x => x.Foo, values); // Act - var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Bar, new[] { Rnd.Lng, Rnd.Lng }); + var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Bar, [Rnd.Lng, Rnd.Lng]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); @@ -61,7 +61,7 @@ public void Values_Not_Equal__Throws_EqualTypeException() fluent.WhereNotIn(x => x.Foo, values); // Act - var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Foo, new[] { Rnd.Str, Rnd.Str }); + var action = (ICall c) => FluentQueryHelper.AssertWhereNotIn(c, x => x.Foo, [Rnd.Str, Rnd.Str]); // Assert Assert.Throws(() => fluent.AssertCalls(action)); diff --git a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetColumnsFromList_Tests.cs b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetColumnsFromList_Tests.cs index b65dac1a4..2ec820128 100644 --- a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetColumnsFromList_Tests.cs +++ b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetColumnsFromList_Tests.cs @@ -29,7 +29,7 @@ public void Escapes_And_Joins_Columns() var client = Substitute.For(); var c0 = Substitute.For(); var c1 = Substitute.For(); - var columns = new ColumnList(new[] { c0, c1 }); + var columns = new ColumnList([c0, c1]); // Act var result = QueryF.GetColumnsFromList(client, columns); diff --git a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetSelectFromList_Tests.cs b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetSelectFromList_Tests.cs index 96a1e9f49..0e915d130 100644 --- a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetSelectFromList_Tests.cs +++ b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetSelectFromList_Tests.cs @@ -30,7 +30,7 @@ public void Escapes_And_Joins_Columns() var client = Substitute.For(); var c0 = Substitute.For(); var c1 = Substitute.For(); - var columns = new ColumnList(new[] { c0, c1 }); + var columns = new ColumnList([c0, c1]); // Act QueryF.GetSelectFromList(client, columns); diff --git a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetWhereAndParameters_Tests.cs b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetWhereAndParameters_Tests.cs index 4d23f679c..962ea6740 100644 --- a/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetWhereAndParameters_Tests.cs +++ b/tests/Tests.Jeebs.Data/Query/Functions/QueryF/GetWhereAndParameters_Tests.cs @@ -18,10 +18,10 @@ public void IncludeTableName_False_Calls_Escape_Column() var column = Substitute.For(); column.ColName.Returns(name); - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ (column, Compare.LessThan, Rnd.Int) - }); + ]); var client = Substitute.ForPartsOf(); @@ -43,10 +43,10 @@ public void IncludeTableName_True_Calls_Escape_Column_And_Table() column.ColName.Returns(columnName); column.TblName.Returns(tableName); - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ (column, Compare.LessThan, Rnd.Int) - }); + ]); var client = Substitute.ForPartsOf(); @@ -75,10 +75,10 @@ public void Operator_Not_In_Adds_Param(Compare input) column.ColName.Returns(name); var value = Rnd.Int; - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ (column, input, value) - }); + ]); var client = Substitute.ForPartsOf(); @@ -109,10 +109,10 @@ public void Operator_Not_In_Adds_StrongId_Param(Compare input) column.ColName.Returns(name); var value = Rnd.Lng; - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ (column, input, new TestId(value)) - }); + ]); var client = Substitute.ForPartsOf(); @@ -131,10 +131,10 @@ private static void Test_In_With_Not_Enumerable(Compare cmp) { // Arrange var column = Substitute.For(); - var predicates = ImmutableList.Create(new (IColumn, Compare, object)[] - { + var predicates = ImmutableList.Create( + [ (column, cmp, Rnd.Int) - }); + ]); var client = Substitute.ForPartsOf(); @@ -169,10 +169,10 @@ private static void Test_In_With_Enumerable(Compare cmp, Func(); diff --git a/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereIn_Tests.cs b/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereIn_Tests.cs index c71c70b22..69de67773 100644 --- a/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereIn_Tests.cs +++ b/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereIn_Tests.cs @@ -36,7 +36,7 @@ public void Adds_Predicate() // Act var r0 = query.WhereIn(nameof(TestEntity.Foo), new[] { v0, v1 }); - var r1 = query.WhereIn(x => x.Foo, new[] { v0, v1 }); + var r1 = query.WhereIn(x => x.Foo, [v0, v1]); // Assert var f0 = Assert.IsType>(r0); diff --git a/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereNotIn_Tests.cs b/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereNotIn_Tests.cs index eecda0d60..40833c4da 100644 --- a/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereNotIn_Tests.cs +++ b/tests/Tests.Jeebs.Data/Query/_/FluentQuery/WhereNotIn_Tests.cs @@ -36,7 +36,7 @@ public void Adds_Predicate() // Act var r0 = query.WhereNotIn(nameof(TestEntity.Foo), new[] { v0, v1 }); - var r1 = query.WhereNotIn(x => x.Foo, new[] { v0, v1 }); + var r1 = query.WhereNotIn(x => x.Foo, [v0, v1]); // Assert var f0 = Assert.IsType>(r0); diff --git a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetClaim_Tests.cs b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetClaim_Tests.cs index 7ba936065..5a1b1a54b 100644 --- a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetClaim_Tests.cs +++ b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetClaim_Tests.cs @@ -52,7 +52,7 @@ public void Claims_Is_Empty__Returns_None_With_ListIsEmptyMsg() public void Claims_Does_Not_Contain__Returns_None_With_NoMatchingItemsMsg() { // Arrange - var principal = Setup(true, new[] { new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str) }); + var principal = Setup(true, [new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str)]); // Act var result = principal.GetClaim(Rnd.Str); @@ -66,7 +66,7 @@ public void Claims_Contains_Multiple__Returns_None_With_MultipleItemsMsg() { // Arrange var type = Rnd.Str; - var principal = Setup(true, new[] { new Claim(type, Rnd.Str), new Claim(type, Rnd.Str) }); + var principal = Setup(true, [new Claim(type, Rnd.Str), new Claim(type, Rnd.Str)]); // Act var result = principal.GetClaim(type); @@ -81,7 +81,7 @@ public void Claims_Contains_Single__Returns_Some_With_Value() // Arrange var type = Rnd.Str; var value = Rnd.Str; - var principal = Setup(true, new[] { new Claim(type, value) }); + var principal = Setup(true, [new Claim(type, value)]); // Act var result = principal.GetClaim(type); diff --git a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetUserId_Tests.cs b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetUserId_Tests.cs index 17cd0a3ba..da6a98af0 100644 --- a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetUserId_Tests.cs +++ b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/GetUserId_Tests.cs @@ -14,7 +14,7 @@ public class GetUserId_Tests : ClaimsPrincipalExtensions_Tests public void Claims_Does_Not_Contain_UserId__Returns_None_With_NoMatchingItemsMsg() { // Arrange - var principal = Setup(true, new[] { new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str) }); + var principal = Setup(true, [new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str)]); // Act var result = principal.GetUserId(); @@ -27,7 +27,7 @@ public void Claims_Does_Not_Contain_UserId__Returns_None_With_NoMatchingItemsMsg public void Claims_Contains_Multiple_UserIds__Returns_None_With_MultipleItemsMsg() { // Arrange - var principal = Setup(true, new[] { new Claim(JwtClaimTypes.UserId, Rnd.Str), new Claim(JwtClaimTypes.UserId, Rnd.Str) }); + var principal = Setup(true, [new Claim(JwtClaimTypes.UserId, Rnd.Str), new Claim(JwtClaimTypes.UserId, Rnd.Str)]); // Act var result = principal.GetUserId(); @@ -40,7 +40,7 @@ public void Claims_Contains_Multiple_UserIds__Returns_None_With_MultipleItemsMsg public void Claims_Contains_Single_UserId__Incorrect_Type__Returns_None_With_InvalidUserIdMsg() { // Arrange - var principal = Setup(true, new[] { new Claim(JwtClaimTypes.UserId, Rnd.Str) }); + var principal = Setup(true, [new Claim(JwtClaimTypes.UserId, Rnd.Str)]); // Act var result = principal.GetUserId(); @@ -54,7 +54,7 @@ public void Claims_Contains_Single_UserId__Correct_Type__Returns_Some_With_AuthU { // Arrange var userId = Rnd.Lng; - var principal = Setup(true, new[] { new Claim(JwtClaimTypes.UserId, userId.ToString()) }); + var principal = Setup(true, [new Claim(JwtClaimTypes.UserId, userId.ToString())]); // Act var result = principal.GetUserId(); diff --git a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/HasClaim_Tests.cs b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/HasClaim_Tests.cs index 6830bdfc5..13237a584 100644 --- a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/HasClaim_Tests.cs +++ b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/HasClaim_Tests.cs @@ -50,7 +50,7 @@ public void Claims_Is_Empty__Returns_False() public void Claims_Does_Not_Contain__Returns_False() { // Arrange - var principal = Setup(true, new[] { new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str) }); + var principal = Setup(true, [new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str)]); // Act var result = principal.HasClaim(Rnd.Str); @@ -64,7 +64,7 @@ public void Claims_Contains_Multiple__Returns_False() { // Arrange var type = Rnd.Str; - var principal = Setup(true, new[] { new Claim(type, Rnd.Str), new Claim(type, Rnd.Str) }); + var principal = Setup(true, [new Claim(type, Rnd.Str), new Claim(type, Rnd.Str)]); // Act var result = principal.HasClaim(type); @@ -79,7 +79,7 @@ public void Claims_Contains_Single__Returns_True() // Arrange var type = Rnd.Str; var value = Rnd.Str; - var principal = Setup(true, new[] { new Claim(type, value) }); + var principal = Setup(true, [new Claim(type, value)]); // Act var result = principal.HasClaim(type); diff --git a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/IsSuper_Tests.cs b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/IsSuper_Tests.cs index 8488641e6..68a3f3c8e 100644 --- a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/IsSuper_Tests.cs +++ b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/IsSuper_Tests.cs @@ -51,7 +51,7 @@ public void Claims_Is_Empty__Returns_False() public void Claims_Does_Not_Contain__Returns_False() { // Arrange - var principal = Setup(true, new[] { new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str) }); + var principal = Setup(true, [new Claim(Rnd.Str, Rnd.Str), new Claim(Rnd.Str, Rnd.Str)]); // Act var result = principal.IsSuper(); @@ -64,7 +64,7 @@ public void Claims_Does_Not_Contain__Returns_False() public void Claims_Contains_Multiple__Returns_False() { // Arrange - var principal = Setup(true, new[] { new Claim(JwtClaimTypes.IsSuper, Rnd.Str), new Claim(JwtClaimTypes.IsSuper, Rnd.Str) }); + var principal = Setup(true, [new Claim(JwtClaimTypes.IsSuper, Rnd.Str), new Claim(JwtClaimTypes.IsSuper, Rnd.Str)]); // Act var result = principal.IsSuper(); @@ -77,7 +77,7 @@ public void Claims_Contains_Multiple__Returns_False() public void Claims_Contains_Single__Returns_True() { // Arrange - var principal = Setup(true, new[] { new Claim(JwtClaimTypes.IsSuper, Rnd.Str) }); + var principal = Setup(true, [new Claim(JwtClaimTypes.IsSuper, Rnd.Str)]); // Act var result = principal.IsSuper(); diff --git a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/_Setup.cs b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/_Setup.cs index 97acd00e6..115f7a4bd 100644 --- a/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/_Setup.cs +++ b/tests/Tests.Jeebs.Mvc.Auth/_/ClaimsPrincipalExtensions/_Setup.cs @@ -10,6 +10,6 @@ public abstract class ClaimsPrincipalExtensions_Tests protected ClaimsPrincipal Setup(bool authenticated, params Claim[]? claims) { var claimsIdentity = new ClaimsIdentity(claims, authenticated ? Rnd.Str : null); - return new(new[] { claimsIdentity }); + return new([claimsIdentity]); } } diff --git a/tests/Tests.Jeebs.Mvc/Models/Menu/MenuF/GetUris_Tests.cs b/tests/Tests.Jeebs.Mvc/Models/Menu/MenuF/GetUris_Tests.cs index 4c190a0d1..ef0f0d4ab 100644 --- a/tests/Tests.Jeebs.Mvc/Models/Menu/MenuF/GetUris_Tests.cs +++ b/tests/Tests.Jeebs.Mvc/Models/Menu/MenuF/GetUris_Tests.cs @@ -52,8 +52,8 @@ public void Calls_GetUri_For_Each_Item_And_Children() var c2 = new MenuItem { Text = Rnd.Str }; var c3 = new MenuItem { Text = Rnd.Str }; var c4 = new MenuItem { Text = Rnd.Str }; - var p0 = new MenuItem { Text = Rnd.Str, Children = new(new[] { c0, c1, c2 }) }; - var p1 = new MenuItem { Text = Rnd.Str, Children = new(new[] { c3, c4 }) }; + var p0 = new MenuItem { Text = Rnd.Str, Children = new([c0, c1, c2]) }; + var p1 = new MenuItem { Text = Rnd.Str, Children = new([c3, c4]) }; var items = new[] { p0, p1 }.ToList(); var getUri = Substitute.For(); getUri.Invoke(urlHelper, Arg.Any()).Returns(x => x.ArgAt(1).Text); diff --git a/tests/Tests.Jeebs/Collections/ImmutableList/GetEnumerator_Tests.cs b/tests/Tests.Jeebs/Collections/ImmutableList/GetEnumerator_Tests.cs index 1233273cd..ea7b0d240 100644 --- a/tests/Tests.Jeebs/Collections/ImmutableList/GetEnumerator_Tests.cs +++ b/tests/Tests.Jeebs/Collections/ImmutableList/GetEnumerator_Tests.cs @@ -11,7 +11,7 @@ public void Returns_Enumerator() // Arrange var i0 = Rnd.Guid; var i1 = Rnd.Guid; - var list = ImmutableList.Create(new[] { i0, i1 }); + var list = ImmutableList.Create([i0, i1]); // Act var result = list.GetEnumerator(); diff --git a/tests/Tests.Jeebs/Collections/ImmutableList/Indexer_Tests.cs b/tests/Tests.Jeebs/Collections/ImmutableList/Indexer_Tests.cs index c0e9df56a..f3b8173ed 100644 --- a/tests/Tests.Jeebs/Collections/ImmutableList/Indexer_Tests.cs +++ b/tests/Tests.Jeebs/Collections/ImmutableList/Indexer_Tests.cs @@ -14,7 +14,7 @@ public void Exists_Returns_Some_With_Value() var i0 = Rnd.Str; var i1 = Rnd.Str; var i2 = Rnd.Str; - var list = ImmutableList.Create(new[] { i0, i1, i2 }); + var list = ImmutableList.Create([i0, i1, i2]); // Act var result = list[1]; @@ -30,7 +30,7 @@ public void Does_Not_Exist_Returns_None_With_ElementAtIsNullMsg() // Arrange var i0 = Rnd.Str; var i1 = Rnd.Str; - var list = ImmutableList.Create(new[] { i0, i1 }); + var list = ImmutableList.Create([i0, i1]); // Act var result = list[2]; @@ -58,7 +58,7 @@ public void Element_Is_Read_Only() // Arrange var i0 = Rnd.Str; var i1 = Rnd.Str; - var list = ImmutableList.Create(new[] { i0, i1 }); + var list = ImmutableList.Create([i0, i1]); // Act for (var i = 0; i < list.Count; i++) diff --git a/tests/Tests.Jeebs/Collections/ImmutableList/WithRange_Tests.cs b/tests/Tests.Jeebs/Collections/ImmutableList/WithRange_Tests.cs index 742790e1a..18de384e3 100644 --- a/tests/Tests.Jeebs/Collections/ImmutableList/WithRange_Tests.cs +++ b/tests/Tests.Jeebs/Collections/ImmutableList/WithRange_Tests.cs @@ -16,7 +16,7 @@ public void Returns_List_With_Items_Added() var list = new ImmutableList(new[] { i0, i1 }); // Act - var result = list.WithRange(new[] { i2, i3 }); + var result = list.WithRange([i2, i3]); // Assert Assert.Collection(result, @@ -38,7 +38,7 @@ public void Returns_New_List_With_Items_Added() var list = new ImmutableList(new[] { i0, i1 }); // Act - var result = list.WithRange(new[] { i2, i3 }); + var result = list.WithRange([i2, i3]); i0 = Rnd.Str; i1 = Rnd.Str; i2 = Rnd.Str; diff --git a/tests/Tests.Jeebs/Collections/ImmutableList/WithoutRange_Tests.cs b/tests/Tests.Jeebs/Collections/ImmutableList/WithoutRange_Tests.cs index b2fc6e3f7..5ede0a1c6 100644 --- a/tests/Tests.Jeebs/Collections/ImmutableList/WithoutRange_Tests.cs +++ b/tests/Tests.Jeebs/Collections/ImmutableList/WithoutRange_Tests.cs @@ -16,7 +16,7 @@ public void Returns_List_With_Items_Removed() var list = new ImmutableList(new[] { i0, i1, i2, i3 }); // Act - var result = list.WithoutRange(new[] { i2, i3 }); + var result = list.WithoutRange([i2, i3]); // Assert Assert.Collection(result, @@ -36,7 +36,7 @@ public void Returns_New_List_With_Items_Removed() var list = new ImmutableList(new[] { i0, i1, i2, i3 }); // Act - var result = list.WithoutRange(new[] { i2, i3 }); + var result = list.WithoutRange([i2, i3]); i0 = Rnd.Str; i1 = Rnd.Str; diff --git a/tests/Tests.Jeebs/Logging/Log/Msg_Tests.cs b/tests/Tests.Jeebs/Logging/Log/Msg_Tests.cs index eb9537d31..a3cd149f0 100644 --- a/tests/Tests.Jeebs/Logging/Log/Msg_Tests.cs +++ b/tests/Tests.Jeebs/Logging/Log/Msg_Tests.cs @@ -158,7 +158,7 @@ public void Calls_For_Each_Msg() msg.Level.Returns(LogLevel.Verbose); // Act - log.Msgs(new[] { msg, msg, msg, msg, msg }); + log.Msgs([msg, msg, msg, msg, msg]); // Assert log.Received(5).Vrb(Arg.Any(), Arg.Any()); From 25967387624fd396518c876f452b71ff2f1437c3 Mon Sep 17 00:00:00 2001 From: bfren Date: Wed, 27 Mar 2024 15:20:21 +0000 Subject: [PATCH 034/202] Moving JsonConverters to internal namespace --- .../JsonConverters/DateTimeJsonConverter.cs | 25 ++++++++--------- .../JsonConverters/EnumeratedJsonConverter.cs | 27 ++++++++++--------- .../EnumeratedJsonConverterFactory.cs | 18 +++++++------ 3 files changed, 37 insertions(+), 33 deletions(-) rename src/Jeebs/{Functions => Internals}/JsonConverters/DateTimeJsonConverter.cs (55%) rename src/Jeebs/{Functions => Internals}/JsonConverters/EnumeratedJsonConverter.cs (55%) rename src/Jeebs/{Functions => Internals}/JsonConverters/EnumeratedJsonConverterFactory.cs (62%) diff --git a/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs b/src/Jeebs/Internals/JsonConverters/DateTimeJsonConverter.cs similarity index 55% rename from src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs rename to src/Jeebs/Internals/JsonConverters/DateTimeJsonConverter.cs index 5147e1ccf..d7ade1b42 100644 --- a/src/Jeebs/Functions/JsonConverters/DateTimeJsonConverter.cs +++ b/src/Jeebs/Internals/JsonConverters/DateTimeJsonConverter.cs @@ -5,31 +5,32 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Jeebs.Functions.JsonConverters; +namespace Jeebs.Internals.JsonConverters; /// -/// JSON converter +/// JSON converter for objects. /// internal sealed class DateTimeJsonConverter : JsonConverter { /// - /// Read value as UTC DateTime + /// Read value as UTC DateTime. /// - /// Utf8JsonReader - /// Type - /// JsonSerializerOptions + /// Utf8JsonReader. + /// Type. + /// JsonSerializerOptions. + /// Parsed DateTime or . public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => M.ParseDateTime(reader.GetString()).Match( - some: x => new DateTime(x.Ticks, DateTimeKind.Utc), - none: DateTime.MinValue.ToUniversalTime + none: DateTime.MinValue.ToUniversalTime, + some: x => x.ToUniversalTime() ); /// - /// Convert to UTC and then to a sortable ('s') formatted string + /// Convert to UTC and then to a sortable ('s') formatted string. /// - /// Utf8JsonWriter - /// DateTime - /// JsonSerializerOptions + /// Utf8JsonWriter. + /// DateTime. + /// JsonSerializerOptions. public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToUniversalTime().ToString("s")); } diff --git a/src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverter.cs b/src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverter.cs similarity index 55% rename from src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverter.cs rename to src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverter.cs index 44c52d04b..c59f4ae1f 100644 --- a/src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverter.cs +++ b/src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverter.cs @@ -5,24 +5,25 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Jeebs.Functions.JsonConverters; +namespace Jeebs.Internals.JsonConverters; /// -/// JSON converter +/// JSON converter for objects. /// -/// Enumerated type +/// Enumerated type. internal sealed class EnumeratedJsonConverter : JsonConverter where T : Enumerated { /// - /// Read an Enumerated type value - which requires the 'name' (value) to be passed in the constructor + /// Read an Enumerated type value - which requires the 'name' (value) to be passed in the constructor. /// - /// Utf8JsonReader - /// Enumerated type - /// JsonSerializerOptions - /// + /// Utf8JsonReader. + /// Enumerated type. + /// JsonSerializerOptions. + /// value. + /// public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => - Activator.CreateInstance(typeToConvert, args: reader.GetString()) switch + Activator.CreateInstance(typeToConvert, reader.GetString()) switch { T x => x, @@ -32,11 +33,11 @@ internal sealed class EnumeratedJsonConverter : JsonConverter }; /// - /// Write an Enumerated type value + /// Write an Enumerated type value. /// - /// Utf8JsonWriter - /// Enumerated value - /// JsonSerializerOptions + /// Utf8JsonWriter. + /// Enumerated value. + /// JsonSerializerOptions. public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString()); } diff --git a/src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverterFactory.cs b/src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverterFactory.cs similarity index 62% rename from src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverterFactory.cs rename to src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverterFactory.cs index 011aa5819..9c8a47070 100644 --- a/src/Jeebs/Functions/JsonConverters/EnumeratedJsonConverterFactory.cs +++ b/src/Jeebs/Internals/JsonConverters/EnumeratedJsonConverterFactory.cs @@ -5,26 +5,28 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Jeebs.Functions.JsonConverters; +namespace Jeebs.Internals.JsonConverters; /// -/// JSON converter factory +/// JSON converter for objects. /// internal sealed class EnumeratedJsonConverterFactory : JsonConverterFactory { /// - /// Returns true if inherits from + /// Returns true if inherits from . /// - /// Type to convert + /// Type to convert. + /// Whether or not inherits from . public override bool CanConvert(Type typeToConvert) => typeToConvert.IsSubclassOf(typeof(Enumerated)); /// - /// Creates JsonConverter using Enum type as generic argument + /// Creates JsonConverter using type as generic argument. /// - /// Enum type - /// JsonSerializerOptions - /// + /// type. + /// JsonSerializerOptions. + /// object. + /// public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var converterType = typeof(EnumeratedJsonConverter<>).MakeGenericType(typeToConvert); From 5faa2cf040c3f2c6d71f1962cccc36420fcf1939 Mon Sep 17 00:00:00 2001 From: bfren Date: Wed, 27 Mar 2024 15:20:44 +0000 Subject: [PATCH 035/202] Making layout and comments consistent --- src/Jeebs/ArrayExtensions.cs | 26 ---- src/Jeebs/DateTimeExtensions.EndOfDay.cs | 17 +++ .../DateTimeExtensions.FirstDayOfMonth.cs | 17 +++ .../DateTimeExtensions.FirstDayOfWeek.cs | 17 +++ .../DateTimeExtensions.LastDayOfMonth.cs | 17 +++ src/Jeebs/DateTimeExtensions.LastDayOfWeek.cs | 17 +++ src/Jeebs/DateTimeExtensions.StartOfDay.cs | 17 +++ .../DateTimeExtensions.ToSortableString.cs | 18 +++ .../DateTimeExtensions.ToStandardString.cs | 18 +++ src/Jeebs/DateTimeExtensions.cs | 60 +-------- src/Jeebs/DateTimeInt.Comparable.cs | 11 ++ src/Jeebs/DateTimeInt.Equatable.cs | 26 ++++ src/Jeebs/DateTimeInt.Operators.cs | 31 +++++ src/Jeebs/DateTimeInt.Parsable.cs | 49 ++++++++ src/Jeebs/DateTimeInt.cs | 117 +++++++----------- .../DateTimeIntExtensions.Deconstruct.cs | 19 +++ src/Jeebs/DateTimeIntExtensions.cs | 9 ++ .../Functions/Base32F.FromBase32String.cs | 1 + src/Jeebs/Functions/Base32F.ToBase32String.cs | 1 + src/Jeebs/Functions/BooleanF.Parse.cs | 6 +- src/Jeebs/Functions/BooleanF.cs | 9 ++ src/Jeebs/Functions/DateTimeF.FromFormat.cs | 1 + src/Jeebs/Functions/DateTimeF.FromUnix.cs | 1 + src/Jeebs/Functions/DateTimeF.UnixEpoch.cs | 1 + src/Jeebs/Functions/EnumF.Convert.cs | 2 + src/Jeebs/Functions/EnumF.Parse.cs | 2 + src/Jeebs/Functions/JsonF.Bool.cs | 1 + src/Jeebs/Functions/JsonF.CopyOptions.cs | 3 +- src/Jeebs/Functions/JsonF.Deserialise.cs | 1 + src/Jeebs/Functions/JsonF.Serialise.cs | 1 + src/Jeebs/Functions/JsonF.cs | 2 +- src/Jeebs/Functions/ListF.Create.cs | 35 ++++++ src/Jeebs/Functions/ListF.Deserialise.cs | 23 ++++ src/Jeebs/Functions/ListF.Empty.cs | 17 +++ src/Jeebs/Functions/ListF.Merge.cs | 19 +++ src/Jeebs/Functions/ListF.cs | 55 +------- src/Jeebs/Functions/MathsF.Combinations.cs | 1 + src/Jeebs/Functions/MathsF.Factorial.cs | 1 + src/Jeebs/Functions/MathsF.Permutations.cs | 1 + src/Jeebs/Functions/PhpF.Deserialise.cs | 11 +- src/Jeebs/Functions/PhpF.Serialise.cs | 3 +- src/Jeebs/Functions/PhpF.cs | 18 +-- src/Jeebs/Functions/StringF.Format.cs | 13 +- src/Jeebs/Functions/StringF.cs | 9 ++ src/Jeebs/Functions/ThreadF.FireAndForget.cs | 7 +- src/Jeebs/Functions/ThreadF.cs | 9 ++ .../TypeF.GetPropertyTypesImplementing.cs | 1 + ...peF.GetPropertyTypesImplementingGeneric.cs | 1 + .../Functions/TypeF.GetTypesImplementing.cs | 1 + .../TypeF.GetTypesImplementingGeneric.cs | 1 + src/Jeebs/Functions/TypeF.cs | 24 ++-- src/Jeebs/Functions/UriF.IsHttp.cs | 10 +- src/Jeebs/Functions/UriF.IsHttps.cs | 11 ++ src/Jeebs/Functions/UriF.cs | 9 ++ .../VersionF.GetJeebsVersionAsync.cs | 1 + src/Jeebs/Functions/VersionF.GetVersion.cs | 2 + src/Jeebs/Logging/ILog.cs | 6 +- src/Jeebs/Logging/StaticLogger.cs | 3 +- .../LinqExpressionExtensions.GetMemberInfo.cs | 31 +++++ ...inqExpressionExtensions.GetPropertyInfo.cs | 35 ++++++ .../Reflection/LinqExpressionExtensions.cs | 48 +------ .../ObjectExtensions.GetProperties.cs | 25 ++++ .../ObjectExtensions.GetPropertyValue.cs | 54 ++++++++ .../ObjectExtensions.HasProperty.cs | 18 +++ src/Jeebs/Reflection/ObjectExtensions.cs | 72 +---------- src/Jeebs/Reflection/PropertyInfo.cs | 54 +++----- .../PropertyInfoExtensions.IsNullable.cs | 17 +++ .../Reflection/PropertyInfoExtensions.cs | 17 +-- 68 files changed, 744 insertions(+), 437 deletions(-) delete mode 100644 src/Jeebs/ArrayExtensions.cs create mode 100644 src/Jeebs/DateTimeExtensions.EndOfDay.cs create mode 100644 src/Jeebs/DateTimeExtensions.FirstDayOfMonth.cs create mode 100644 src/Jeebs/DateTimeExtensions.FirstDayOfWeek.cs create mode 100644 src/Jeebs/DateTimeExtensions.LastDayOfMonth.cs create mode 100644 src/Jeebs/DateTimeExtensions.LastDayOfWeek.cs create mode 100644 src/Jeebs/DateTimeExtensions.StartOfDay.cs create mode 100644 src/Jeebs/DateTimeExtensions.ToSortableString.cs create mode 100644 src/Jeebs/DateTimeExtensions.ToStandardString.cs create mode 100644 src/Jeebs/DateTimeInt.Comparable.cs create mode 100644 src/Jeebs/DateTimeInt.Equatable.cs create mode 100644 src/Jeebs/DateTimeInt.Operators.cs create mode 100644 src/Jeebs/DateTimeInt.Parsable.cs create mode 100644 src/Jeebs/DateTimeIntExtensions.Deconstruct.cs create mode 100644 src/Jeebs/DateTimeIntExtensions.cs create mode 100644 src/Jeebs/Functions/BooleanF.cs create mode 100644 src/Jeebs/Functions/ListF.Create.cs create mode 100644 src/Jeebs/Functions/ListF.Deserialise.cs create mode 100644 src/Jeebs/Functions/ListF.Empty.cs create mode 100644 src/Jeebs/Functions/ListF.Merge.cs create mode 100644 src/Jeebs/Functions/StringF.cs create mode 100644 src/Jeebs/Functions/ThreadF.cs create mode 100644 src/Jeebs/Functions/UriF.IsHttps.cs create mode 100644 src/Jeebs/Functions/UriF.cs create mode 100644 src/Jeebs/Reflection/LinqExpressionExtensions.GetMemberInfo.cs create mode 100644 src/Jeebs/Reflection/LinqExpressionExtensions.GetPropertyInfo.cs create mode 100644 src/Jeebs/Reflection/ObjectExtensions.GetProperties.cs create mode 100644 src/Jeebs/Reflection/ObjectExtensions.GetPropertyValue.cs create mode 100644 src/Jeebs/Reflection/ObjectExtensions.HasProperty.cs create mode 100644 src/Jeebs/Reflection/PropertyInfoExtensions.IsNullable.cs diff --git a/src/Jeebs/ArrayExtensions.cs b/src/Jeebs/ArrayExtensions.cs deleted file mode 100644 index 42aac66ad..000000000 --- a/src/Jeebs/ArrayExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Jeebs Rapid Application Development -// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 - -namespace Jeebs; - -/// -/// Extension methods for objects. -/// -public static class ArrayExtensions -{ - /// - /// Extend an array with additional items - /// - /// Type - /// Original array - /// Additional items - public static T[] ExtendWith(this T[] @this, params T[] additionalItems) - { - if (additionalItems is null || additionalItems.Length == 0) - { - return @this; - } - - return [.. @this, .. additionalItems]; - } -} diff --git a/src/Jeebs/DateTimeExtensions.EndOfDay.cs b/src/Jeebs/DateTimeExtensions.EndOfDay.cs new file mode 100644 index 000000000..72586cd27 --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.EndOfDay.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return one second to midnight on the specified day. + /// + /// DateTime object. + /// One second to midnight on . + public static DateTime EndOfDay(this DateTime @this) => + new(@this.Year, @this.Month, @this.Day, 23, 59, 59, @this.Kind); +} diff --git a/src/Jeebs/DateTimeExtensions.FirstDayOfMonth.cs b/src/Jeebs/DateTimeExtensions.FirstDayOfMonth.cs new file mode 100644 index 000000000..6aa8825f8 --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.FirstDayOfMonth.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return midnight on the first day of the month for the specified date. + /// + /// DateTime object. + /// Midnight on the first day of the month specified by . + public static DateTime FirstDayOfMonth(this DateTime @this) => + new(@this.Year, @this.Month, 1, 0, 0, 0, @this.Kind); +} diff --git a/src/Jeebs/DateTimeExtensions.FirstDayOfWeek.cs b/src/Jeebs/DateTimeExtensions.FirstDayOfWeek.cs new file mode 100644 index 000000000..ef1716cbc --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.FirstDayOfWeek.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return midnight on the first day of the week for the specified date. + /// + /// DateTime object. + /// Midnight on the first day of the week specified by . + public static DateTime FirstDayOfWeek(this DateTime @this) => + @this.AddDays((int)@this.DayOfWeek * -1).StartOfDay(); +} diff --git a/src/Jeebs/DateTimeExtensions.LastDayOfMonth.cs b/src/Jeebs/DateTimeExtensions.LastDayOfMonth.cs new file mode 100644 index 000000000..56e9d6341 --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.LastDayOfMonth.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return one minute to midnight on the last day of the month for the specified date. + /// + /// DateTime object. + /// One second to midnight on the last day of the month specified by . + public static DateTime LastDayOfMonth(this DateTime @this) => + new DateTime(@this.Year, @this.Month, 1, 23, 59, 59, @this.Kind).AddMonths(1).AddDays(-1); +} diff --git a/src/Jeebs/DateTimeExtensions.LastDayOfWeek.cs b/src/Jeebs/DateTimeExtensions.LastDayOfWeek.cs new file mode 100644 index 000000000..bece7099e --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.LastDayOfWeek.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return one minute to midnight on the last day of the week for the specified date. + /// + /// DateTime object. + /// One second to midnight on the last day of the week specified by . + public static DateTime LastDayOfWeek(this DateTime @this) => + @this.AddDays(6 - (int)@this.DayOfWeek).EndOfDay(); +} diff --git a/src/Jeebs/DateTimeExtensions.StartOfDay.cs b/src/Jeebs/DateTimeExtensions.StartOfDay.cs new file mode 100644 index 000000000..bc7a0793b --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.StartOfDay.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return midnight on the specified day. + /// + /// DateTime object. + /// Midnight on . + public static DateTime StartOfDay(this DateTime @this) => + new(@this.Year, @this.Month, @this.Day, 0, 0, 0, @this.Kind); +} diff --git a/src/Jeebs/DateTimeExtensions.ToSortableString.cs b/src/Jeebs/DateTimeExtensions.ToSortableString.cs new file mode 100644 index 000000000..916444a07 --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.ToSortableString.cs @@ -0,0 +1,18 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; +using System.Globalization; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return a sortable format date/time value (yyyy-MM-dd HH:mm:ss.ffff). + /// + /// DateTime object. + /// Sortable DateTime string. + public static string ToSortableString(this DateTime @this) => + @this.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss.ffff", CultureInfo.InvariantCulture); +} diff --git a/src/Jeebs/DateTimeExtensions.ToStandardString.cs b/src/Jeebs/DateTimeExtensions.ToStandardString.cs new file mode 100644 index 000000000..3feb9580c --- /dev/null +++ b/src/Jeebs/DateTimeExtensions.ToStandardString.cs @@ -0,0 +1,18 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; +using System.Globalization; + +namespace Jeebs; + +public static partial class DateTimeExtensions +{ + /// + /// Return a standard format date/time value (HH:mm dd/MM/yyyy). + /// + /// DateTime object. + /// Standard DateTime string. + public static string ToStandardString(this DateTime @this) => + @this.ToString("HH:mm dd/MM/yyyy", CultureInfo.InvariantCulture); +} diff --git a/src/Jeebs/DateTimeExtensions.cs b/src/Jeebs/DateTimeExtensions.cs index e108e14ef..9a7ece08d 100644 --- a/src/Jeebs/DateTimeExtensions.cs +++ b/src/Jeebs/DateTimeExtensions.cs @@ -2,68 +2,10 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 using System; -using System.Globalization; namespace Jeebs; /// /// Extension methods for objects. /// -public static class DateTimeExtensions -{ - /// - /// Return midnight on the specified day - /// - /// DateTime object - public static DateTime StartOfDay(this DateTime @this) => - new(@this.Year, @this.Month, @this.Day, 0, 0, 0, @this.Kind); - - /// - /// Return one second to midnight on the specified day - /// - /// DateTime object - public static DateTime EndOfDay(this DateTime @this) => - new(@this.Year, @this.Month, @this.Day, 23, 59, 59, @this.Kind); - - /// - /// Return midnight on the first day of the week for the specified date - /// - /// DateTime object - public static DateTime FirstDayOfWeek(this DateTime @this) => - @this.AddDays((int)@this.DayOfWeek * -1).StartOfDay(); - - /// - /// Return one minute to midnight on the last day of the week for the specified date - /// - /// DateTime object - public static DateTime LastDayOfWeek(this DateTime @this) => - @this.AddDays(6 - (int)@this.DayOfWeek).EndOfDay(); - - /// - /// Return midnight on the first day of the month for the specified date - /// - /// DateTime object - public static DateTime FirstDayOfMonth(this DateTime @this) => - new(@this.Year, @this.Month, 1, 0, 0, 0, @this.Kind); - - /// - /// Return one minute to midnight on the last day of the month for the specified date - /// - /// DateTime object - public static DateTime LastDayOfMonth(this DateTime @this) => - new DateTime(@this.Year, @this.Month, 1, 23, 59, 59, @this.Kind).AddMonths(1).AddDays(-1); - - /// - /// Return a standard format date/time value (HH:mm dd/MM/yyyy) - /// - /// DateTime object - public static string ToSortableString(this DateTime @this) => - @this.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss.ffff", CultureInfo.InvariantCulture); - - /// - /// Return a standard format date/time value (HH:mm dd/MM/yyyy) - /// - /// DateTime object - public static string ToStandardString(this DateTime @this) => - @this.ToString("HH:mm dd/MM/yyyy", CultureInfo.InvariantCulture); -} +public static partial class DateTimeExtensions { } diff --git a/src/Jeebs/DateTimeInt.Comparable.cs b/src/Jeebs/DateTimeInt.Comparable.cs new file mode 100644 index 000000000..ac326697d --- /dev/null +++ b/src/Jeebs/DateTimeInt.Comparable.cs @@ -0,0 +1,11 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs; + +public readonly partial struct DateTimeInt +{ + /// + public int CompareTo(DateTimeInt other) => + ToLong().CompareTo(other.ToLong()); +} diff --git a/src/Jeebs/DateTimeInt.Equatable.cs b/src/Jeebs/DateTimeInt.Equatable.cs new file mode 100644 index 000000000..992df8500 --- /dev/null +++ b/src/Jeebs/DateTimeInt.Equatable.cs @@ -0,0 +1,26 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs; + +public readonly partial struct DateTimeInt +{ + /// + public bool Equals(DateTimeInt other) => + (Year, Month, Day, Hour, Minute) == (other.Year, other.Month, other.Day, other.Hour, other.Minute); + + /// + public override bool Equals(object? obj) => + obj switch + { + DateTimeInt x => + Equals(other: x), + + _ => + false + }; + + /// + public override int GetHashCode() => + Year.GetHashCode() ^ Month.GetHashCode() ^ Day.GetHashCode() ^ Hour.GetHashCode() ^ Minute.GetHashCode(); +} diff --git a/src/Jeebs/DateTimeInt.Operators.cs b/src/Jeebs/DateTimeInt.Operators.cs new file mode 100644 index 000000000..055b638fb --- /dev/null +++ b/src/Jeebs/DateTimeInt.Operators.cs @@ -0,0 +1,31 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs; + +public readonly partial struct DateTimeInt +{ + /// + public static bool operator ==(DateTimeInt left, DateTimeInt right) => + left.Equals(right); + + /// + public static bool operator !=(DateTimeInt left, DateTimeInt right) => + !(left == right); + + /// + public static bool operator <(DateTimeInt left, DateTimeInt right) => + left.CompareTo(right) < 0; + + /// + public static bool operator <=(DateTimeInt left, DateTimeInt right) => + left.CompareTo(right) <= 0; + + /// + public static bool operator >(DateTimeInt left, DateTimeInt right) => + left.CompareTo(right) > 0; + + /// + public static bool operator >=(DateTimeInt left, DateTimeInt right) => + left.CompareTo(right) >= 0; +} diff --git a/src/Jeebs/DateTimeInt.Parsable.cs b/src/Jeebs/DateTimeInt.Parsable.cs new file mode 100644 index 000000000..925837572 --- /dev/null +++ b/src/Jeebs/DateTimeInt.Parsable.cs @@ -0,0 +1,49 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Jeebs; + +public readonly partial struct DateTimeInt +{ + /// + public static DateTimeInt Parse(string s, IFormatProvider? provider) + { + ArgumentException.ThrowIfNullOrEmpty(s); + + if (s.Length != 12) + { + throw new ArgumentException($"{nameof(DateTimeInt)} value must be a 12 characters long", nameof(s)); + } + + if (!ulong.TryParse(s, out _)) + { + throw new ArgumentException("Not a valid number", nameof(s)); + } + + return new( + year: int.Parse(s[0..4], provider: provider), + month: int.Parse(s[4..6], provider: provider), + day: int.Parse(s[6..8], provider: provider), + hour: int.Parse(s[8..10], provider: provider), + minute: int.Parse(s[10..], provider: provider) + ); + } + + /// + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out DateTimeInt result) + { + try + { + result = Parse(s!, provider); + return true; + } + catch (Exception) + { + result = MinValue; + return false; + } + } +} diff --git a/src/Jeebs/DateTimeInt.cs b/src/Jeebs/DateTimeInt.cs index 35b5c11de..a70631802 100644 --- a/src/Jeebs/DateTimeInt.cs +++ b/src/Jeebs/DateTimeInt.cs @@ -8,84 +8,68 @@ namespace Jeebs; /// -/// DateTime Integer +/// DateTime Integer format. /// -public sealed record class DateTimeInt +public readonly partial struct DateTimeInt : IComparable, IEquatable, IParsable { /// - /// Twelve numbers: YYYYMMDDhhmm + /// Twelve numbers: yyyymmddHHMM. /// private const string FormatString = "000000000000"; /// - /// January, March, May, July, August, October, December + /// Year. /// - private static readonly int[] ThirtyOneDayMonths = [1, 3, 5, 7, 8, 10, 12]; - - /// - /// April, June, September, November - /// - private static readonly int[] ThirtyDayMonths = [4, 6, 9, 11]; - - /// - /// Year - /// - public int Year { get; init; } - - /// - /// Month - /// - public int Month { get; init; } + public int Year { get; init; } = 0; /// - /// Day + /// Month. /// - public int Day { get; init; } + public int Month { get; init; } = 0; /// - /// Hour + /// Day. /// - public int Hour { get; init; } + public int Day { get; init; } = 0; /// - /// Minute + /// Hour. /// - public int Minute { get; init; } + public int Hour { get; init; } = 0; /// - /// Construct using zero values + /// Minute. /// - public DateTimeInt() => - (Year, Month, Day, Hour, Minute) = (0, 0, 0, 0, 0); + public int Minute { get; init; } = 0; /// - /// Construct object using specified date/time integers + /// Construct object using specified date/time integers. /// - /// Year - /// Month - /// Day - /// Hour - /// Minute + /// Year. + /// Month. + /// Day. + /// Hour. + /// Minute. public DateTimeInt(int year, int month, int day, int hour, int minute) => (Year, Month, Day, Hour, Minute) = (year, month, day, hour, minute); /// - /// Construct object using a DateTime object + /// Construct object using a DateTime object. /// - /// DateTime + /// DateTime. public DateTimeInt(DateTime dt) : this(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute) { } /// - /// Construct object from string - must be exactly 12 characters long (yyyymmddHHMM) + /// Construct object from string - must be exactly 12 characters long (yyyymmddHHMM). /// - /// DateTime string value - format yyyymmddHHMM + /// DateTime string value - format yyyymmddHHMM. public DateTimeInt(string value) => - (Year, Month, Day, Hour, Minute) = Parse(value); + (Year, Month, Day, Hour, Minute) = Parse(value, null); /// - /// Construct object from long - will be converted to a 12-digit string with leading zeroes + /// Construct object from long - will be converted to a 12-digit string with leading zeroes. /// - /// DateTime long value - format yyyymmddHHMM + /// DateTime long value - format yyyymmddHHMM. public DateTimeInt(long value) { if (value <= 100000000000) @@ -98,12 +82,13 @@ public DateTimeInt(long value) throw new ArgumentException("Too large - cannot be later than the year 9999", nameof(value)); } - (Year, Month, Day, Hour, Minute) = Parse(value.ToString(FormatString, CultureInfo.InvariantCulture)); + (Year, Month, Day, Hour, Minute) = Parse(value.ToString(FormatString, null), null); } /// - /// Get the current DateTime + /// Get DateTime. /// + /// Value as a object. public Result ToDateTime() => IsValidDateTime() switch { @@ -115,9 +100,10 @@ public Result ToDateTime() => }; /// - /// Outputs object values as correctly formatted string - /// If the object is not valid, returns a string of zeroes + /// Outputs object values as correctly formatted string. + /// If the object is not valid, returns a string of zeroes. /// + /// String value. public override string ToString() => IsValidDateTime().Valid switch { @@ -129,9 +115,10 @@ public override string ToString() => }; /// - /// Outputs object values as long - /// If the object is not valid, returns 0 + /// Outputs object values as long. + /// If the object is not valid, returns 0. /// + /// Long value. public long ToLong() => IsValidDateTime().Valid switch { @@ -216,7 +203,7 @@ internal static bool IsLeapYear(int year) /// Minimum possible value /// public static DateTimeInt MinValue => - new(0, 0, 0, 0, 0); + new(); /// /// Maximum possible value @@ -224,31 +211,15 @@ internal static bool IsLeapYear(int year) public static DateTimeInt MaxValue => new(9999, 12, 31, 23, 59); - private static (int year, int month, int day, int hour, int minute) Parse(string value) - { - if (string.IsNullOrEmpty(value)) - { - return (0, 0, 0, 0, 0); - } - - if (value.Length != 12) - { - throw new ArgumentException($"{nameof(DateTimeInt)} value must be a 12 characters long", nameof(value)); - } - - if (!ulong.TryParse(value, out _)) - { - throw new ArgumentException("Not a valid number", nameof(value)); - } + /// + /// January, March, May, July, August, October, December. + /// + private static readonly int[] ThirtyOneDayMonths = [1, 3, 5, 7, 8, 10, 12]; - return ( - year: int.Parse(value[0..4], CultureInfo.InvariantCulture), - month: int.Parse(value[4..6], CultureInfo.InvariantCulture), - day: int.Parse(value[6..8], CultureInfo.InvariantCulture), - hour: int.Parse(value[8..10], CultureInfo.InvariantCulture), - minute: int.Parse(value[10..], CultureInfo.InvariantCulture) - ); - } + /// + /// April, June, September, November. + /// + private static readonly int[] ThirtyDayMonths = [4, 6, 9, 11]; #endregion Static diff --git a/src/Jeebs/DateTimeIntExtensions.Deconstruct.cs b/src/Jeebs/DateTimeIntExtensions.Deconstruct.cs new file mode 100644 index 000000000..ad56fb3ee --- /dev/null +++ b/src/Jeebs/DateTimeIntExtensions.Deconstruct.cs @@ -0,0 +1,19 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs; + +public static partial class DateTimeIntExtensions +{ + /// + /// Deconstruct into values. + /// + /// DateTimeInt object. + /// Year. + /// Month. + /// Day. + /// Hour. + /// Minute. + public static void Deconstruct(this DateTimeInt @this, out int year, out int month, out int day, out int hour, out int minute) => + (year, month, day, hour, minute) = (@this.Year, @this.Month, @this.Day, @this.Hour, @this.Minute); +} diff --git a/src/Jeebs/DateTimeIntExtensions.cs b/src/Jeebs/DateTimeIntExtensions.cs new file mode 100644 index 000000000..8aeeb81a7 --- /dev/null +++ b/src/Jeebs/DateTimeIntExtensions.cs @@ -0,0 +1,9 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs; + +/// +/// Extension methods for objects. +/// +public static partial class DateTimeIntExtensions { } diff --git a/src/Jeebs/Functions/Base32F.FromBase32String.cs b/src/Jeebs/Functions/Base32F.FromBase32String.cs index b58b4ed4f..d7c74fa57 100644 --- a/src/Jeebs/Functions/Base32F.FromBase32String.cs +++ b/src/Jeebs/Functions/Base32F.FromBase32String.cs @@ -11,6 +11,7 @@ public static partial class Base32F /// Convert string to a byte array. /// /// Base32 string to convert - must be at least two characters. + /// Byte array. public static Result FromBase32String(string base32String) { static Result fail(string message, params object[] args) => diff --git a/src/Jeebs/Functions/Base32F.ToBase32String.cs b/src/Jeebs/Functions/Base32F.ToBase32String.cs index db18ee497..8d7e90165 100644 --- a/src/Jeebs/Functions/Base32F.ToBase32String.cs +++ b/src/Jeebs/Functions/Base32F.ToBase32String.cs @@ -12,6 +12,7 @@ public static partial class Base32F /// Convert to a Base32 string. /// /// Input byte array. + /// Base32 string. public static string ToBase32String(byte[] bytes) { // Check if byte array is null diff --git a/src/Jeebs/Functions/BooleanF.Parse.cs b/src/Jeebs/Functions/BooleanF.Parse.cs index 30dcf1ead..e89b754c9 100644 --- a/src/Jeebs/Functions/BooleanF.Parse.cs +++ b/src/Jeebs/Functions/BooleanF.Parse.cs @@ -6,16 +6,14 @@ namespace Jeebs.Functions; -/// -/// Boolean functions. -/// -public static class BooleanF +public static partial class BooleanF { /// /// Parse a boolean value. /// /// Value type. /// Value to parse. + /// Boolean value. public static Maybe Parse(T value) { // Convert to string diff --git a/src/Jeebs/Functions/BooleanF.cs b/src/Jeebs/Functions/BooleanF.cs new file mode 100644 index 000000000..5144fc4fa --- /dev/null +++ b/src/Jeebs/Functions/BooleanF.cs @@ -0,0 +1,9 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +namespace Jeebs.Functions; + +/// +/// Boolean functions. +/// +public static partial class BooleanF { } diff --git a/src/Jeebs/Functions/DateTimeF.FromFormat.cs b/src/Jeebs/Functions/DateTimeF.FromFormat.cs index d227ed1f1..ad7c6a2c2 100644 --- a/src/Jeebs/Functions/DateTimeF.FromFormat.cs +++ b/src/Jeebs/Functions/DateTimeF.FromFormat.cs @@ -13,6 +13,7 @@ public static partial class DateTimeF /// /// Input string. /// DateTime format. + /// DateTime object. public static Maybe FromFormat(string s, string format) { if (DateTime.TryParseExact(s, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt)) diff --git a/src/Jeebs/Functions/DateTimeF.FromUnix.cs b/src/Jeebs/Functions/DateTimeF.FromUnix.cs index 660b43aa5..816e0cf06 100644 --- a/src/Jeebs/Functions/DateTimeF.FromUnix.cs +++ b/src/Jeebs/Functions/DateTimeF.FromUnix.cs @@ -11,6 +11,7 @@ public static partial class DateTimeF /// Convert a Unix timestamp to a DateTime object. /// /// Unix timestamp (in seconds). + /// DateTime object. public static DateTime FromUnix(double unixTimeStampInSeconds) => DateTime.UnixEpoch.AddSeconds(unixTimeStampInSeconds).ToUniversalTime(); } diff --git a/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs b/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs index 90bb5bdcc..fbe86d1c2 100644 --- a/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs +++ b/src/Jeebs/Functions/DateTimeF.UnixEpoch.cs @@ -10,6 +10,7 @@ public static partial class DateTimeF /// /// Returns a DateTime object representing the start of the Unix Epoch. /// + /// DateTime object representing the start of the Unix Epoch. public static DateTime UnixEpoch() => new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); } diff --git a/src/Jeebs/Functions/EnumF.Convert.cs b/src/Jeebs/Functions/EnumF.Convert.cs index 35c8d2f3f..262b0ef07 100644 --- a/src/Jeebs/Functions/EnumF.Convert.cs +++ b/src/Jeebs/Functions/EnumF.Convert.cs @@ -13,6 +13,7 @@ public static partial class EnumF /// /// Enum type. /// The value to parse. + /// object. public static FluentConvert Convert(TFrom value) where TFrom : struct, Enum => new(value); @@ -31,6 +32,7 @@ public sealed class FluentConvert(TFrom from) /// Convert value to specified type. /// /// Convert To type. + /// Value converted to object. public Result To() where TTo : struct, Enum { diff --git a/src/Jeebs/Functions/EnumF.Parse.cs b/src/Jeebs/Functions/EnumF.Parse.cs index f60926154..7614989c7 100644 --- a/src/Jeebs/Functions/EnumF.Parse.cs +++ b/src/Jeebs/Functions/EnumF.Parse.cs @@ -12,6 +12,7 @@ public static partial class EnumF /// /// Enum type. /// The value to parse. + /// parsed as a Enum value. public static Maybe Parse(string? value) where T : struct, Enum { @@ -42,6 +43,7 @@ public static Maybe Parse(string? value) /// /// Enum type. /// The value to parse. + /// parsed as an Enum value of type . public static Maybe Parse(Type t, string? value) { if (!t.IsEnum) diff --git a/src/Jeebs/Functions/JsonF.Bool.cs b/src/Jeebs/Functions/JsonF.Bool.cs index 482fc8476..0eb4e3cc4 100644 --- a/src/Jeebs/Functions/JsonF.Bool.cs +++ b/src/Jeebs/Functions/JsonF.Bool.cs @@ -9,6 +9,7 @@ public static partial class JsonF /// Return lower-case boolean string. /// /// Boolean value. + /// JSON boolean string. public static string Bool(bool value) => value switch { diff --git a/src/Jeebs/Functions/JsonF.CopyOptions.cs b/src/Jeebs/Functions/JsonF.CopyOptions.cs index 52bdcae3d..47872bcd9 100644 --- a/src/Jeebs/Functions/JsonF.CopyOptions.cs +++ b/src/Jeebs/Functions/JsonF.CopyOptions.cs @@ -8,8 +8,9 @@ namespace Jeebs.Functions; public static partial class JsonF { /// - /// Get a copy of the default serialiser options. + /// Get a copy of the default JSON serialiser options. /// + /// Default JSON seraliser options. public static JsonSerializerOptions CopyOptions() { var copy = new JsonSerializerOptions diff --git a/src/Jeebs/Functions/JsonF.Deserialise.cs b/src/Jeebs/Functions/JsonF.Deserialise.cs index 53bfa0ad7..a17de49a8 100644 --- a/src/Jeebs/Functions/JsonF.Deserialise.cs +++ b/src/Jeebs/Functions/JsonF.Deserialise.cs @@ -14,6 +14,7 @@ public static partial class JsonF /// The type of the object to return. /// The string to deserialise. /// JsonSerializerOptions. + /// Deserialised object. public static Result Deserialise(string str, JsonSerializerOptions options) { static Result fail(string message) => diff --git a/src/Jeebs/Functions/JsonF.Serialise.cs b/src/Jeebs/Functions/JsonF.Serialise.cs index 7956b6fed..99f4d2315 100644 --- a/src/Jeebs/Functions/JsonF.Serialise.cs +++ b/src/Jeebs/Functions/JsonF.Serialise.cs @@ -13,6 +13,7 @@ public static partial class JsonF /// Object Type to be serialised. /// The object to serialise. /// JsonSerializerOptions. + /// Serialised string. public static Result Serialise(T obj, JsonSerializerOptions options) => obj switch { diff --git a/src/Jeebs/Functions/JsonF.cs b/src/Jeebs/Functions/JsonF.cs index 99d94049a..dcb3a8f49 100644 --- a/src/Jeebs/Functions/JsonF.cs +++ b/src/Jeebs/Functions/JsonF.cs @@ -3,7 +3,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Jeebs.Functions.JsonConverters; +using Jeebs.Internals.JsonConverters; using Wrap.Json; namespace Jeebs.Functions; diff --git a/src/Jeebs/Functions/ListF.Create.cs b/src/Jeebs/Functions/ListF.Create.cs new file mode 100644 index 000000000..9df3c70f1 --- /dev/null +++ b/src/Jeebs/Functions/ListF.Create.cs @@ -0,0 +1,35 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Collections.Generic; +using Jeebs.Collections; + +namespace Jeebs.Functions; + +public static partial class ListF +{ + /// + /// Create a new with the specified . + /// + /// List Item type. + /// Collection of items to add. + /// New containing . + public static ImmutableList Create(IEnumerable items) => + new(items); + + /// + /// Create a new with the specified . + /// + /// List Item type. + /// Items to add. + /// New containing . + public static ImmutableList Create(params T[]? args) => + args switch + { + T[] => + new(args), + + _ => + new() + }; +} diff --git a/src/Jeebs/Functions/ListF.Deserialise.cs b/src/Jeebs/Functions/ListF.Deserialise.cs new file mode 100644 index 000000000..68f909a29 --- /dev/null +++ b/src/Jeebs/Functions/ListF.Deserialise.cs @@ -0,0 +1,23 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Collections.Generic; +using Jeebs.Collections; + +namespace Jeebs.Functions; + +public static partial class ListF +{ + /// + /// Deserialise a JSON list into an ImmutableList. + /// + /// List Item type. + /// JSON list. + /// Deserialised object. + public static ImmutableList Deserialise(string json) => + JsonF.Deserialise>(json) + .Match( + fail: _ => new(), + ok: x => Create(items: x) + ); +} diff --git a/src/Jeebs/Functions/ListF.Empty.cs b/src/Jeebs/Functions/ListF.Empty.cs new file mode 100644 index 000000000..9852d3949 --- /dev/null +++ b/src/Jeebs/Functions/ListF.Empty.cs @@ -0,0 +1,17 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using Jeebs.Collections; + +namespace Jeebs.Functions; + +public static partial class ListF +{ + /// + /// Create an empty . + /// + /// List Item type. + /// Empty . + public static ImmutableList Empty() => + new(); +} diff --git a/src/Jeebs/Functions/ListF.Merge.cs b/src/Jeebs/Functions/ListF.Merge.cs new file mode 100644 index 000000000..7a9e27813 --- /dev/null +++ b/src/Jeebs/Functions/ListF.Merge.cs @@ -0,0 +1,19 @@ +// Jeebs Rapid Application Development +// Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 + +using System.Linq; +using Jeebs.Collections; + +namespace Jeebs.Functions; + +public static partial class ListF +{ + /// + /// Merge multiple objects into one. + /// + /// List Item type. + /// Lists to merge. + /// Merged lists. + public static ImmutableList Merge(params IImmutableList[] lists) => + new(lists.SelectMany(x => x)); +} diff --git a/src/Jeebs/Functions/ListF.cs b/src/Jeebs/Functions/ListF.cs index ba1487968..4fa177966 100644 --- a/src/Jeebs/Functions/ListF.cs +++ b/src/Jeebs/Functions/ListF.cs @@ -1,8 +1,6 @@ // Jeebs Rapid Application Development // Copyright (c) bfren - licensed under https://mit.bfren.dev/2013 -using System.Collections.Generic; -using System.Linq; using Jeebs.Collections; namespace Jeebs.Functions; @@ -10,55 +8,4 @@ namespace Jeebs.Functions; /// /// Alternative methods for creating and manipulating objects. /// -public static class ListF -{ - /// - /// Create an empty . - /// - /// List Item type. - public static ImmutableList Empty() => - new(); - - /// - /// Create a new with the specified . - /// - /// List Item type. - /// Collection of items to add. - public static ImmutableList Create(IEnumerable items) => - new(items); - - /// - /// Create a new with the specified . - /// - /// List Item type. - /// Items to add. - public static ImmutableList Create(params T[]? args) => - args switch - { - T[] => - new(args), - - _ => - new() - }; - - /// - /// Deserialise a JSON list into an ImmutableList. - /// - /// List Item type. - /// JSON list. - public static ImmutableList Deserialise(string json) => - JsonF.Deserialise>(json) - .Match( - ok: x => Create(items: x), - fail: _ => new() - ); - - /// - /// Merge multiple objects into one. - /// - /// List Item type. - /// Lists to merge. - public static ImmutableList Merge(params IImmutableList[] lists) => - new(lists.SelectMany(x => x)); -} +public static partial class ListF { } diff --git a/src/Jeebs/Functions/MathsF.Combinations.cs b/src/Jeebs/Functions/MathsF.Combinations.cs index 65d32be8c..8e73234e5 100644 --- a/src/Jeebs/Functions/MathsF.Combinations.cs +++ b/src/Jeebs/Functions/MathsF.Combinations.cs @@ -16,6 +16,7 @@ public static partial class MathsF /// /// The total number of objects. /// The number of objects being selected. + /// The number of possible combinations. public static long Combinations(long n, long r) => (n > 0 && r > 0 && n >= r) switch { diff --git a/src/Jeebs/Functions/MathsF.Factorial.cs b/src/Jeebs/Functions/MathsF.Factorial.cs index 3d00712d8..230055a38 100644 --- a/src/Jeebs/Functions/MathsF.Factorial.cs +++ b/src/Jeebs/Functions/MathsF.Factorial.cs @@ -12,6 +12,7 @@ public static partial class MathsF /// must be greater than or equal to zero. /// /// Number (greater than or equal to zero). + /// Factorial result. public static long Factorial(long x) { if (x < 0) diff --git a/src/Jeebs/Functions/MathsF.Permutations.cs b/src/Jeebs/Functions/MathsF.Permutations.cs index e43e61b57..a43625b9b 100644 --- a/src/Jeebs/Functions/MathsF.Permutations.cs +++ b/src/Jeebs/Functions/MathsF.Permutations.cs @@ -16,6 +16,7 @@ public static partial class MathsF /// /// The total number of objects. /// The number of places being filled. + /// The number of possible permutations. public static long Permutations(long n, long r) => (n > 0 && r > 0 && n >= r) switch { diff --git a/src/Jeebs/Functions/PhpF.Deserialise.cs b/src/Jeebs/Functions/PhpF.Deserialise.cs index 05d9e9c3c..72ba6dc17 100644 --- a/src/Jeebs/Functions/PhpF.Deserialise.cs +++ b/src/Jeebs/Functions/PhpF.Deserialise.cs @@ -9,9 +9,10 @@ namespace Jeebs.Functions; public static partial class PhpF { /// - /// Deserialise object. + /// Deserialise object from a PHP string. /// /// Serialised string. + /// Deserialised object. public static object Deserialise(string str) { var pointer = 0; @@ -102,7 +103,7 @@ static string getString(string str, ref int pointer) } // Get AssocArray - static AssocArray getArray(string str, ref int pointer) + static AssociativeArray getArray(string str, ref int pointer) { // Get start and end positions var colon0 = str.IndexOf(':', pointer) + 1; @@ -112,13 +113,13 @@ static AssocArray getArray(string str, ref int pointer) pointer += 4 + num.Length; // Get each key and value, and add them to a hashtable - var table = new AssocArray(); + var table = new AssociativeArray(); for (var i = 0; i < len; i++) { var (key, value) = (PrivateDeserialise(str, ref pointer), PrivateDeserialise(str, ref pointer)); M.ParseInt32(key.ToString()).Match( - some: x => table.Add(x, value), - none: () => table.Add(key, value) + none: () => table.Add(key, value), + some: x => table.Add(x, value) ); } diff --git a/src/Jeebs/Functions/PhpF.Serialise.cs b/src/Jeebs/Functions/PhpF.Serialise.cs index 848647003..f6dd016e4 100644 --- a/src/Jeebs/Functions/PhpF.Serialise.cs +++ b/src/Jeebs/Functions/PhpF.Serialise.cs @@ -10,10 +10,11 @@ namespace Jeebs.Functions; public static partial class PhpF { /// - /// Serialise object. + /// Serialise object as PHP string.. /// /// Object type. /// Object value. + /// Serialised string. public static string Serialise(T obj) => Serialise(obj, new StringBuilder()).ToString(); diff --git a/src/Jeebs/Functions/PhpF.cs b/src/Jeebs/Functions/PhpF.cs index 0b1c4b48f..04331eb23 100644 --- a/src/Jeebs/Functions/PhpF.cs +++ b/src/Jeebs/Functions/PhpF.cs @@ -12,42 +12,42 @@ namespace Jeebs.Functions; public static partial class PhpF { /// - /// Array type + /// Array type. /// public static readonly char ArrayChar = 'a'; /// - /// Boolean type + /// Boolean type. /// public static readonly char BooleanChar = 'b'; /// - /// Double type + /// Double type. /// public static readonly char DoubleChar = 'd'; /// - /// Integer type + /// Integer type. /// public static readonly char IntegerChar = 'i'; /// - /// String type + /// String type. /// public static readonly char StringChar = 's'; /// - /// Null type + /// Null type. /// public static readonly char NullChar = 'N'; /// - /// UTF8Encoding + /// UTF8Encoding. /// private static readonly Encoding UTF8 = new UTF8Encoding(); /// - /// Alias for use in deserialising associative arrays + /// Alias for use in deserialising associative arrays. /// - public sealed class AssocArray : Dictionary { } + public sealed class AssociativeArray : Dictionary { } } diff --git a/src/Jeebs/Functions/StringF.Format.cs b/src/Jeebs/Functions/StringF.Format.cs index 6bf4c6098..38a894b8c 100644 --- a/src/Jeebs/Functions/StringF.Format.cs +++ b/src/Jeebs/Functions/StringF.Format.cs @@ -8,9 +8,6 @@ namespace Jeebs.Functions; -/// -/// String functions. -/// public static partial class StringF { /// @@ -20,6 +17,7 @@ public static partial class StringF /// Object type. /// Format string. /// Object (nullable). + /// Formatted string. public static string Format(string formatString, T obj, string? ifNull) => obj switch { @@ -34,12 +32,15 @@ public static string Format(string formatString, T obj, string? ifNull) => /// Works like string.Format() but with named as well as numbered placeholders. /// Source is Array: values will be inserted in order (regardless of placeholder values). /// Source is Object: property names must match placeholders or they will be left in place. - /// Inspired by http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables. - /// (Significantly) altered to work without requiring DataBinder. /// + /// + /// Inspired by http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables, + /// (significantly) altered to work without requiring DataBinder. + /// /// Source type. /// String to format. /// Source object to use for template values. + /// Formatted string. public static string Format(string formatString, T source) { // Return original if source is null or if it is an empty array @@ -94,7 +95,7 @@ public static string Format(string formatString, T source) + new string('}', endGroup.Captures.Count); }); - return string.Format(CultureInfo.InvariantCulture, rewrittenFormat, values.ToArray()); + return string.Format(CultureInfo.InvariantCulture, rewrittenFormat, [.. values]); } [GeneratedRegex("(?\\{)+(?