#nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace ShrinkCommand { public static class ShrinkCommandRegHelper { public static void RegisterStaticCommands(ShrinkCommandService service) { if (service == null) throw new ArgumentNullException(nameof(service)); RegisterStaticCommandSubscriberTypes(service, ShrinkCommandGeneratedRegistry.GetStaticSubscriberTypes()); } public static void RegisterCommands(ShrinkCommandService service, object? target) { if (service == null) throw new ArgumentNullException(nameof(service)); RegisterCommandsInternal(service, target); } public static void RegisterStaticCommandSubscriberTypes( ShrinkCommandService service, IEnumerable subscriberTypes) { if (service == null) throw new ArgumentNullException(nameof(service)); if (subscriberTypes == null) throw new ArgumentNullException(nameof(subscriberTypes)); foreach (var type in subscriberTypes) { if (type == null || type.GetCustomAttribute(false) == null) continue; ScanMethodsAndRegister(service, null, type, type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); } } private static void RegisterCommandsInternal(ShrinkCommandService service, object? target) { if (target == null) return; var ownerType = target.GetType(); if (ownerType.GetCustomAttribute(false) == null) return; ScanMethodsAndRegister(service, target, ownerType, ownerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); } private static void ScanMethodsAndRegister( ShrinkCommandService service, object? target, Type ownerType, MethodInfo[] methods) { foreach (var method in methods) { if (target != null && method.IsStatic) continue; var attributes = method.GetCustomAttributes(typeof(ShrinkCommandAttribute), false) .Cast() .ToArray(); if (attributes.Length == 0) continue; foreach (var attribute in attributes) { try { service.RegisterCommand(new ShrinkCommandRegistration { Path = attribute.Path, Aliases = attribute.Aliases ?? Array.Empty(), Description = attribute.Description, Permission = attribute.Permission, SourceKind = attribute.SourceKind, Hidden = attribute.Hidden, Handler = ShrinkCommandMethodAdapter.BuildHandler(target, method, ParseArgumentNames(attribute.Path)) }); } catch (Exception ex) { ShrinkCommandLogger.Warn( $"[ShrinkCommand] Failed to register {ownerType.FullName}.{method.Name}: {ex.Message}"); } } } } private static string[] ParseArgumentNames(string path) { return path.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) .Where(token => token.Length >= 3 && token[0] == '<' && token[token.Length - 1] == '>') .Select(token => { var name = token.Substring(1, token.Length - 2).Trim(); if (name.EndsWith("...", StringComparison.Ordinal)) name = name.Substring(0, name.Length - 3).Trim(); return name; }) .ToArray(); } } }