diff --git a/README.md b/README.md index ce6bb8f..2b08fdd 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ The `PhoneNumber` struct encapsulates parsing, validation, and formatting of pho Key features: -- Implements `IStringWithRegexValueObject` for parsing and validation. +- Implements `IRegexValueObject` for parsing and validation. - Leverages `libphonenumber` for parsing into components. - Provides implicit conversions to/from string. - Generates a tel: URI from the number. diff --git a/Tests/PrimitivesTests.cs b/Tests/PrimitivesTests.cs index 9ee33ae..7a2dae2 100644 --- a/Tests/PrimitivesTests.cs +++ b/Tests/PrimitivesTests.cs @@ -7,7 +7,7 @@ namespace Dgmjr.Primitives.Tests; public abstract class PrimitivesTests : ILog - where TPrimitive : IStringWithRegexValueObject + where TPrimitive : IRegexValueObject where TSelf : PrimitivesTests { public ILogger Logger { get; } diff --git a/src/Abstractions/IResourceIdentifier.cs b/src/Abstractions/IResourceIdentifier.cs index 1903d42..4084927 100644 --- a/src/Abstractions/IResourceIdentifier.cs +++ b/src/Abstractions/IResourceIdentifier.cs @@ -2,6 +2,15 @@ namespace Dgmjr.Abstractions; public interface IResourceIdentifier { + /// The of the resource identifier (if it exists), or otherwise. string? Scheme { get; } + + /// The of the resource identifier (if it exists), or otherwise. string? PathAndQuery { get; } + + /// + /// "" iff they were included in the original string, or otherwise. + /// + /// // + string? DoubleSlashes { get; } } diff --git a/src/Abstractions/IResourceIdentifierWithAuthorityHostPortQueryAndFragment.cs b/src/Abstractions/IResourceIdentifierWithAuthorityHostPortQueryAndFragment.cs index d305ee2..4848252 100644 --- a/src/Abstractions/IResourceIdentifierWithAuthorityHostPortQueryAndFragment.cs +++ b/src/Abstractions/IResourceIdentifierWithAuthorityHostPortQueryAndFragment.cs @@ -3,12 +3,6 @@ namespace Dgmjr.Abstractions; public interface IResourceIdentifierWithAuthorityHostPortQueryAndFragment : IResourceIdentifierWithQueryAndFragment { - /// - /// "" iff they were included in the original string, or otherwise. - /// - /// // - string? DoubleSlashes { get; } - /// /// The (user authentication) component of the resource identifier (if it exists), or otherwise. /// diff --git a/src/Abstractions/IStringWithRegexValueObject.cs b/src/Abstractions/IStringWithRegexValueObject.cs index 5a0a2d0..af5d61b 100644 --- a/src/Abstractions/IStringWithRegexValueObject.cs +++ b/src/Abstractions/IStringWithRegexValueObject.cs @@ -3,7 +3,7 @@ namespace System; #if !NETSTANDARD2_0_OR_GREATER using Validation = global::Validation; #endif -public interface IStringWithRegexValueObject +public interface IRegexValueObject : IComparable, IComparable, IEquatable, @@ -13,7 +13,7 @@ public interface IStringWithRegexValueObject IParsable, IUriConvertible #endif - where TSelf : IStringWithRegexValueObject + where TSelf : IRegexValueObject { /// Gets The value of the value object as a string. Will be or iff == string Value { get; } diff --git a/src/Dgmjr.Primitives.csproj b/src/Dgmjr.Primitives.csproj index 3dabde9..aa44c68 100644 --- a/src/Dgmjr.Primitives.csproj +++ b/src/Dgmjr.Primitives.csproj @@ -53,4 +53,7 @@ + + + diff --git a/src/EmailAddress.cs b/src/EmailAddress.cs index 91f6734..fa3154b 100644 --- a/src/EmailAddress.cs +++ b/src/EmailAddress.cs @@ -33,7 +33,7 @@ namespace System.Net.Mail; )] [StructLayout(LayoutKind.Auto)] [EmailAddress.JConverter] -public partial record struct EmailAddress : IStringWithRegexValueObject, IFormattable +public partial record struct EmailAddress : IRegexValueObject, IFormattable { /// /// The example value string. @@ -60,27 +60,27 @@ public partial record struct EmailAddress : IStringWithRegexValueObject /// Gets the description. /// - static string IStringWithRegexValueObject.Description => Description; + static string IRegexValueObject.Description => Description; /// /// Gets the example value. /// - static EmailAddress IStringWithRegexValueObject.ExampleValue => + static EmailAddress IRegexValueObject.ExampleValue => From(ExampleValueString); /// /// Gets the regex string. /// - static string IStringWithRegexValueObject.RegexString => RegexString; + static string IRegexValueObject.RegexString => RegexString; public static ExternalDocsTuple ExternalDocs => ("Email Address", new Uri("https://en.wikipedia.org/wiki/Email_address")); #else - readonly Regx IStringWithRegexValueObject.Regex() => Regex(); + readonly Regx IRegexValueObject.Regex() => Regex(); - readonly string IStringWithRegexValueObject.RegexString => RegexString; - readonly string IStringWithRegexValueObject.Description => Description; - readonly EmailAddress IStringWithRegexValueObject.ExampleValue => + readonly string IRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly EmailAddress IRegexValueObject.ExampleValue => From(ExampleValueString); #endif diff --git a/src/ObjectId.cs b/src/ObjectId.cs index 4baa66c..6002cc6 100644 --- a/src/ObjectId.cs +++ b/src/ObjectId.cs @@ -34,7 +34,7 @@ namespace System; )] // [RegexDto(ObjectId.RegexString)] public readonly partial record struct ObjectId - : IStringWithRegexValueObject, + : IRegexValueObject, IComparable, IComparable, IEquatable @@ -42,7 +42,7 @@ public readonly partial record struct ObjectId public const string Description = "A ObjectId is a 24-digit (96-bit) hexadecimal string that uniquely identifies an object in a database"; #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.Description => Description; + static string IRegexValueObject.Description => Description; #endif public const string EmptyValue = "000000000000000000000000"; public const int Length = 24; @@ -77,7 +77,7 @@ public readonly partial record struct ObjectId public string OriginalString { get; init; } #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.RegexString => RegexString; + static string IRegexValueObject.RegexString => RegexString; #endif public const string ExampleValueString = "abcdef0123456789abcdef01"; @@ -88,13 +88,13 @@ public readonly partial record struct ObjectId }; #if !NET6_0_OR_GREATER - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); - readonly string IStringWithRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.RegexString => RegexString; - readonly string IStringWithRegexValueObject.Description => Description; + readonly string IRegexValueObject.Description => Description; - readonly ObjectId IStringWithRegexValueObject.ExampleValue => ExampleValue; + readonly ObjectId IRegexValueObject.ExampleValue => ExampleValue; #endif public static ObjectId Parse(string s) => diff --git a/src/OpenApiRegistrations.cs b/src/OpenApiRegistrations.cs index ed7a1cc..31cfd8b 100644 --- a/src/OpenApiRegistrations.cs +++ b/src/OpenApiRegistrations.cs @@ -23,7 +23,7 @@ public static class OpenApiRegistrations { #if NET6_0_OR_GREATER public static WebApplicationBuilder Describe(this WebApplicationBuilder builder) - where T : IStringWithRegexValueObject + where T : IRegexValueObject { builder.Services.Describe(); return builder; @@ -32,7 +32,7 @@ public static WebApplicationBuilder Describe(this WebApplicationBuilder build #if NETSTANDARD2_0_OR_GREATER public static IServiceCollection Describe(this IServiceCollection services) - where T : IStringWithRegexValueObject + where T : IRegexValueObject { services.ConfigureSwaggerGen(options => { @@ -74,10 +74,10 @@ as IEnumerable // options.SchemaGeneratorOptions.CustomTypeMappings[typeof(T)] = () => new OpenApiSchema // { // Type = "string", - // Pattern = typeof(T).GetRuntimeProperty(nameof(IStringWithRegexValueObject.RegexString)).GetValue(null) as string, + // Pattern = typeof(T).GetRuntimeProperty(nameof(IRegexValueObject.RegexString)).GetValue(null) as string, // Format = typeof(T).Name, - // Description = typeof(T).GetRuntimeProperty(nameof(IStringWithRegexValueObject.Description)).GetValue(null) as string, - // Example = new OpenApiString(typeof(T).GetRuntimeProperty(nameof(IStringWithRegexValueObject.ExampleValue)).GetValue(null).ToString()) + // Description = typeof(T).GetRuntimeProperty(nameof(IRegexValueObject.Description)).GetValue(null) as string, + // Example = new OpenApiString(typeof(T).GetRuntimeProperty(nameof(IRegexValueObject.ExampleValue)).GetValue(null).ToString()) // }; #endif }); @@ -85,7 +85,7 @@ as IEnumerable } #else public static IServiceCollection Describe(this IServiceCollection services) - where T : IStringWithRegexValueObject + where T : IRegexValueObject { throw new PlatformNotSupportedException("This feature is not supported by this framework. Upgrade to .NET Standard 2.0 or higher to use it."); } diff --git a/src/PhoneNumber.cs b/src/PhoneNumber.cs index 285e26d..983ffa2 100644 --- a/src/PhoneNumber.cs +++ b/src/PhoneNumber.cs @@ -43,7 +43,7 @@ namespace System.Domain; )] [StructLayout(LayoutKind.Auto)] [PhoneNumber.JConverter] -public partial record struct PhoneNumber : IStringWithRegexValueObject +public partial record struct PhoneNumber : IRegexValueObject { /// /// The string that will be prefixed to the number when converting it to a URI @@ -86,12 +86,12 @@ public static PhoneNumber FromUri(Uri u) => }; #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.RegexString => RegexString; - static string IStringWithRegexValueObject.Description => Description; + static string IRegexValueObject.RegexString => RegexString; + static string IRegexValueObject.Description => Description; #else - readonly string IStringWithRegexValueObject.RegexString => RegexString; - readonly string IStringWithRegexValueObject.Description => Description; - readonly PhoneNumber IStringWithRegexValueObject.ExampleValue => ExampleValue; + readonly string IRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly PhoneNumber IRegexValueObject.ExampleValue => ExampleValue; #endif public override readonly string ToString() => @@ -134,11 +134,11 @@ or InvalidOperationException public static partial Regex Regex(); #elif NET6_0_OR_GREATER public static Regex Regex() => new(RegexString, RegexOptions); - // Regex IStringWithRegexValueObject.RegexString => Regex(); + // Regex IRegexValueObject.RegexString => Regex(); #else private static readonly Regex _regex = new(RegexString, RegexOptions); - readonly Regex IStringWithRegexValueObject.Regex() => _regex; + readonly Regex IRegexValueObject.Regex() => _regex; #endif public static implicit operator PhoneNumber?(string? s) => @@ -175,7 +175,7 @@ public static Validation Validate(string s) => #else public static Validation Validate(string s) => Util.IsViablePhoneNumber(s) - && ((IStringWithRegexValueObject)ExampleValue).Regex().IsMatch(s) + && ((IRegexValueObject)ExampleValue).Regex().IsMatch(s) ? Validation.Ok : Validation.Invalid("Phone number is not valid."); #endif diff --git a/src/iri.cs b/src/iri.cs index fc38635..abe9494 100644 --- a/src/iri.cs +++ b/src/iri.cs @@ -22,17 +22,17 @@ namespace System; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Validation = Vogen.Validation; using Vogen; +#endif -/// -/// Represents an "internationalized resource identifier (IRI)" -/// +/// Represents an "internationalized resource identifier" (IRI) +#if NETSTANDARD2_0_OR_GREATER [RegexDto(_RegexString, RegexOptions: uri._RegexOptions)] [SystemTextJsonConverter] [StructLayout(LayoutKind.Auto)] #endif [DebuggerDisplay("{ToString()}")] public readonly partial record struct iri - : IStringWithRegexValueObject, + : IRegexValueObject, IResourceIdentifierWithAuthorityHostPortQueryAndFragment #if NET7_0_OR_GREATER , @@ -71,16 +71,16 @@ public readonly partial record struct iri public readonly string Value => ToString(); #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.RegexString => RegexString; - static string IStringWithRegexValueObject.Description => Description; - static iri IStringWithRegexValueObject.Empty => EmptyStringValue; - static iri IStringWithRegexValueObject.ExampleValue => new(ExampleStringValue); + static string IRegexValueObject.RegexString => RegexString; + static string IRegexValueObject.Description => Description; + static iri IRegexValueObject.Empty => EmptyStringValue; + static iri IRegexValueObject.ExampleValue => new(ExampleStringValue); #else - readonly string IStringWithRegexValueObject.Description => Description; - readonly iri IStringWithRegexValueObject.ExampleValue => ExampleStringValue; - readonly string IStringWithRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly iri IRegexValueObject.ExampleValue => ExampleStringValue; + readonly string IRegexValueObject.RegexString => RegexString; - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); #endif // public static iri Parse(string iri) => From(iri); diff --git a/src/uri.cs b/src/uri.cs index 7c9a9d7..d416686 100644 --- a/src/uri.cs +++ b/src/uri.cs @@ -32,16 +32,14 @@ namespace System; #if !NETSTANDARD2_0_OR_GREATER using Validation = global::Validation; #endif -/// -/// Represents an "uniform resource identifier (URI)" -/// +/// Represents a "uniform resource identifier" (URI) [RegexDto(uri._RegexString, RegexOptions: uri._RegexOptions)] [uri.JConverter] [DebuggerDisplay("{ToString()}")] [StructLayout(LayoutKind.Auto)] #if NET6_0_OR_GREATER #endif -public readonly partial record struct uri : IStringWithRegexValueObject, IResourceIdentifier +public readonly partial record struct uri : IRegexValueObject, IResourceIdentifier #if NET7_0_OR_GREATER , IUriConvertible @@ -80,22 +78,18 @@ namespace System; public readonly string Value => ToString(); #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.RegexString => RegexString; - static string IStringWithRegexValueObject.Description => Description; - static uri IStringWithRegexValueObject.Empty => EmptyStringValue; - static uri IStringWithRegexValueObject.ExampleValue => new(ExampleStringValue); + static string IRegexValueObject.RegexString => RegexString; + static string IRegexValueObject.Description => Description; + static uri IRegexValueObject.Empty => EmptyStringValue; + static uri IRegexValueObject.ExampleValue => new(ExampleStringValue); - static uri IStringWithRegexValueObject.Parse(string s) => - From(s) with - { - OriginalString = s - }; + static uri IRegexValueObject.Parse(string s) => From(s) with { OriginalString = s }; #else - readonly string IStringWithRegexValueObject.Description => Description; - readonly uri IStringWithRegexValueObject.ExampleValue => ExampleStringValue; - readonly string IStringWithRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly uri IRegexValueObject.ExampleValue => ExampleStringValue; + readonly string IRegexValueObject.RegexString => RegexString; - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); #endif public readonly Uri Uri => this; diff --git a/src/url.cs b/src/url.cs index 59a5202..a06549d 100644 --- a/src/url.cs +++ b/src/url.cs @@ -28,15 +28,13 @@ namespace System; #if !NETSTANDARD2_0_OR_GREATER using Validation = global::Validation; #endif -/// -/// Represents an "uniform resource locator (URL)" -/// +/// Represents a "uniform resource locator" (URL) [RegexDto(url._RegexString, RegexOptions: uri._RegexOptions)] [url.JConverter] [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("{ToString()}")] public readonly partial record struct url - : IStringWithRegexValueObject, + : IRegexValueObject, IResourceIdentifierWithQueryAndFragment #if NET7_0_OR_GREATER , @@ -71,15 +69,15 @@ public readonly partial record struct url public readonly string Value => ToString(); #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.Description => Description; - static string IStringWithRegexValueObject.RegexString => RegexString; - static url IStringWithRegexValueObject.ExampleValue => ExampleStringValue; + static string IRegexValueObject.Description => Description; + static string IRegexValueObject.RegexString => RegexString; + static url IRegexValueObject.ExampleValue => ExampleStringValue; #else - readonly string IStringWithRegexValueObject.Description => Description; - readonly url IStringWithRegexValueObject.ExampleValue => ExampleStringValue; - readonly string IStringWithRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly url IRegexValueObject.ExampleValue => ExampleStringValue; + readonly string IRegexValueObject.RegexString => RegexString; - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); #endif public readonly Uri Uri => this; diff --git a/src/urn.cs b/src/urn.cs index 9576ca7..2b14e78 100644 --- a/src/urn.cs +++ b/src/urn.cs @@ -25,19 +25,18 @@ namespace System; using static System.Text.RegularExpressions.RegexOptions; -/// -/// /// Represents an "uniform resource name" -/// -[RegexDto(urn._RegexString, RegexOptions: uri._RegexOptions)] +/// Represents an "uniform resource name" (URN) +[RegexDto(_RegexString, RegexOptions: uri._RegexOptions)] [JsonConverter(typeof(urn.JsonConverter))] [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("{ToString()}")] -public readonly partial record struct urn : IStringWithRegexValueObject, IResourceIdentifier +public readonly partial record struct urn : IRegexValueObject, IResourceIdentifier #if NET7_0_OR_GREATER , IUriConvertible #endif { + public readonly string? DoubleSlashes { get; } = null; public const string Description = "a uniform resource name (urn)"; #if NET7_0_OR_GREATER @@ -63,21 +62,20 @@ namespace System; public static urn Empty => From(EmptyStringValue); public readonly bool IsEmpty => BaseToString() == EmptyStringValue; public readonly string PathAndQuery => $"{Namespace}:{NamespaceSpecificString}"; - public readonly string? DoubleSlashes = null; public readonly string Value => ToString(); #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.Description => Description; - static string IStringWithRegexValueObject.RegexString => RegexString; - static urn IStringWithRegexValueObject.Empty => EmptyStringValue; - static urn IStringWithRegexValueObject.ExampleValue => new(ExampleStringValue); + static string IRegexValueObject.Description => Description; + static string IRegexValueObject.RegexString => RegexString; + static urn IRegexValueObject.Empty => EmptyStringValue; + static urn IRegexValueObject.ExampleValue => new(ExampleStringValue); #else - readonly string IStringWithRegexValueObject.Description => Description; - readonly urn IStringWithRegexValueObject.ExampleValue => ExampleStringValue; + readonly string IRegexValueObject.Description => Description; + readonly urn IRegexValueObject.ExampleValue => ExampleStringValue; - // urn IStringWithRegexValueObject.Empty => EmptyValue; - readonly string IStringWithRegexValueObject.RegexString => RegexString; + // urn IRegexValueObject.Empty => EmptyValue; + readonly string IRegexValueObject.RegexString => RegexString; - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); #endif // public static urn Parse(string urn) => From(urn); diff --git a/src/xri.cs b/src/xri.cs index 3856d8c..ebb8188 100644 --- a/src/xri.cs +++ b/src/xri.cs @@ -26,13 +26,11 @@ namespace System; using Validation = global::Validation; #endif -/// -/// Represents an "extensible resource identifier" -/// +/// Represents an "eXtensible resource identifier" (XRI) [RegexDto(xri._RegexString, RegexOptions: uri._RegexOptions)] [StructLayout(LayoutKind.Auto)] public readonly partial record struct xri - : IStringWithRegexValueObject, + : IRegexValueObject, IResourceIdentifierWithQueryAndFragment #if NET7_0_OR_GREATER , @@ -70,15 +68,15 @@ public readonly partial record struct xri public readonly string Value { get; init; } #if NET6_0_OR_GREATER - static string IStringWithRegexValueObject.Description => Description; - static string IStringWithRegexValueObject.RegexString => RegexString; - static xri IStringWithRegexValueObject.ExampleValue => ExampleStringValue; + static string IRegexValueObject.Description => Description; + static string IRegexValueObject.RegexString => RegexString; + static xri IRegexValueObject.ExampleValue => ExampleStringValue; #else - readonly string IStringWithRegexValueObject.Description => Description; - readonly xri IStringWithRegexValueObject.ExampleValue => ExampleStringValue; - readonly string IStringWithRegexValueObject.RegexString => RegexString; + readonly string IRegexValueObject.Description => Description; + readonly xri IRegexValueObject.ExampleValue => ExampleStringValue; + readonly string IRegexValueObject.RegexString => RegexString; - readonly Regex IStringWithRegexValueObject.Regex() => Regex(); + readonly Regex IRegexValueObject.Regex() => Regex(); #endif public readonly Uri Uri => this;