using System.Reflection; namespace Prefab.Endpoints; /// /// Provides utility methods for generating standardized endpoint names based on type and module information. /// /// This class is intended for internal use to construct endpoint names that reflect the module and /// feature structure of the application. The generated names are typically used for routing, messaging, or service /// registration scenarios where consistent naming conventions are required. Endpoint names are constructed using the /// namespace or assembly segments of the provided type, followed by the specified endpoint name. internal static class EndpointName { /// /// Gets the default name for the specified type parameter. /// /// The type for which to retrieve the default name. /// A string containing the default name of the type parameter . public static string For() => For(typeof(T).Name); /// /// Gets the endpoint name for the specified type and endpoint identifier. /// /// The type for which to retrieve the endpoint name. /// The logical name of the endpoint. Cannot be null or empty. /// A string representing the endpoint name associated with the specified type and endpoint identifier. public static string For(string endpointName) => For(typeof(T), endpointName); /// /// Generates a fully qualified endpoint name by combining the module segments derived from the specified type with /// the provided endpoint name. /// /// The type from which to resolve module segments. Typically, represents the class or module associated with the /// endpoint. /// The name of the endpoint to append. Cannot be null, empty, or consist only of white-space characters. /// A string representing the fully qualified endpoint name in the format 'Module.Segment.EndpointName'. /// Thrown if endpointName is null, empty, or consists only of white-space characters. public static string For(Type type, string endpointName) { if (string.IsNullOrWhiteSpace(endpointName)) { throw new ArgumentException("Endpoint name cannot be null or whitespace.", nameof(endpointName)); } var segments = ResolveModuleSegments(type); return $"{string.Join('.', segments)}.{endpointName}"; } private static string[] ResolveModuleSegments(MemberInfo type) { if (type is Type concreteType) { var namespaceSegments = ExtractNamespaceSegments(concreteType.Namespace); if (namespaceSegments.Length > 0) { return namespaceSegments; } } var assemblySegments = ExtractNamespaceSegments(type.Module?.Assembly?.GetName().Name); return assemblySegments.Length > 0 ? assemblySegments : [type.Name]; } private static string[] ExtractNamespaceSegments(string? root) { if (string.IsNullOrWhiteSpace(root)) { return []; } var segments = root.Split('.', StringSplitOptions.RemoveEmptyEntries); // Convention: Prefab..(App.)... return segments .SkipWhile(segment => string.Equals(segment, "Prefab", StringComparison.Ordinal)) .Where(segment => !string.Equals(segment, "App", StringComparison.Ordinal)) .ToArray(); } }