private void RegisterCommands(Type t, CommandGroupBuilder currentParent, out List <CommandBuilder> foundCommands) { var ti = t.GetTypeInfo(); var lifespan = ti.GetCustomAttribute <ModuleLifespanAttribute>(); var moduleLifespan = lifespan != null ? lifespan.Lifespan : ModuleLifespan.Singleton; var module = new CommandModuleBuilder() .WithType(t) .WithLifespan(moduleLifespan) .Build(this.Services); // restrict parent lifespan to more or equally restrictive if (currentParent?.Module is TransientCommandModule && moduleLifespan != ModuleLifespan.Transient) { throw new InvalidOperationException("In a transient module, child modules can only be transient."); } // check if we are anything var groupBuilder = new CommandGroupBuilder(module); var isModule = false; var moduleAttributes = ti.GetCustomAttributes(); var moduleHidden = false; var moduleChecks = new List <CheckBaseAttribute>(); foreach (var xa in moduleAttributes) { switch (xa) { case GroupAttribute g: isModule = true; var moduleName = g.Name; if (moduleName == null) { moduleName = ti.Name; if (moduleName.EndsWith("Group") && moduleName != "Group") { moduleName = moduleName.Substring(0, moduleName.Length - 5); } else if (moduleName.EndsWith("Module") && moduleName != "Module") { moduleName = moduleName.Substring(0, moduleName.Length - 6); } else if (moduleName.EndsWith("Commands") && moduleName != "Commands") { moduleName = moduleName.Substring(0, moduleName.Length - 8); } } if (!this.Config.CaseSensitive) { moduleName = moduleName.ToLowerInvariant(); } groupBuilder.WithName(moduleName); foreach (var mi in ti.DeclaredMethods.Where(x => x.IsCommandCandidate(out _) && x.GetCustomAttribute <GroupCommandAttribute>() != null)) { groupBuilder.WithOverload(new CommandOverloadBuilder(mi)); } break; case AliasesAttribute a: foreach (var xalias in a.Aliases) { groupBuilder.WithAlias(this.Config.CaseSensitive ? xalias : xalias.ToLowerInvariant()); } break; case HiddenAttribute h: groupBuilder.WithHiddenStatus(true); moduleHidden = true; break; case DescriptionAttribute d: groupBuilder.WithDescription(d.Description); break; case CheckBaseAttribute c: moduleChecks.Add(c); groupBuilder.WithExecutionCheck(c); break; default: groupBuilder.WithCustomAttribute(xa); break; } } if (!isModule) { groupBuilder = null; } // candidate methods var methods = ti.DeclaredMethods; var commands = new List <CommandBuilder>(); var commandBuilders = new Dictionary <string, CommandBuilder>(); foreach (var m in methods) { if (!m.IsCommandCandidate(out _)) { continue; } var attrs = m.GetCustomAttributes(); if (!(attrs.FirstOrDefault(xa => xa is CommandAttribute) is CommandAttribute cattr)) { continue; } var commandName = cattr.Name; if (commandName == null) { commandName = m.Name; if (commandName.EndsWith("Async") && commandName != "Async") { commandName = commandName.Substring(0, commandName.Length - 5); } } if (!this.Config.CaseSensitive) { commandName = commandName.ToLowerInvariant(); } if (!commandBuilders.TryGetValue(commandName, out var commandBuilder)) { commandBuilders.Add(commandName, commandBuilder = new CommandBuilder(module).WithName(commandName)); if (!isModule) { if (currentParent != null) { currentParent.WithChild(commandBuilder); } else { commands.Add(commandBuilder); } } else { groupBuilder.WithChild(commandBuilder); } } commandBuilder.WithOverload(new CommandOverloadBuilder(m)); if (!isModule && moduleChecks.Any()) { foreach (var chk in moduleChecks) { commandBuilder.WithExecutionCheck(chk); } } foreach (var xa in attrs) { switch (xa) { case AliasesAttribute a: foreach (var xalias in a.Aliases) { commandBuilder.WithAlias(this.Config.CaseSensitive ? xalias : xalias.ToLowerInvariant()); } break; case CheckBaseAttribute p: commandBuilder.WithExecutionCheck(p); break; case DescriptionAttribute d: commandBuilder.WithDescription(d.Description); break; case HiddenAttribute h: commandBuilder.WithHiddenStatus(true); break; default: commandBuilder.WithCustomAttribute(xa); break; } } if (!isModule && moduleHidden) { commandBuilder.WithHiddenStatus(true); } } // candidate types var types = ti.DeclaredNestedTypes .Where(xt => xt.IsModuleCandidateType() && xt.DeclaredConstructors.Any(xc => xc.IsPublic)); foreach (var type in types) { this.RegisterCommands(type.AsType(), groupBuilder, out var tempCommands); if (isModule && tempCommands != null) { foreach (var xtcmd in tempCommands) { groupBuilder.WithChild(xtcmd); } } else if (tempCommands != null) { commands.AddRange(tempCommands); } } if (isModule && currentParent == null) { commands.Add(groupBuilder); } else if (isModule) { currentParent.WithChild(groupBuilder); } foundCommands = commands; }
private void RegisterCommands(Type t, CommandGroupBuilder currentParent, out List <CommandBuilder> commands) { var ti = t.GetTypeInfo(); var lifespan = ti.GetCustomAttribute <ModuleLifespanAttribute>(); var module = new CommandModuleBuilder() .WithType(t) .WithLifespan(lifespan != null ? lifespan.Lifespan : ModuleLifespan.Singleton) .Build(this.Services); // check if we are anything var cgbldr = new CommandGroupBuilder(module); var is_mdl = false; var mdl_attrs = ti.GetCustomAttributes(); var mdl_hidden = false; var mdl_chks = new List <CheckBaseAttribute>(); foreach (var xa in mdl_attrs) { switch (xa) { case GroupAttribute g: is_mdl = true; var mdl_name = g.Name; if (mdl_name == null) { mdl_name = ti.Name; if (mdl_name.EndsWith("Group") && mdl_name != "Group") { mdl_name = mdl_name.Substring(0, mdl_name.Length - 5); } else if (mdl_name.EndsWith("Module") && mdl_name != "Module") { mdl_name = mdl_name.Substring(0, mdl_name.Length - 6); } else if (mdl_name.EndsWith("Commands") && mdl_name != "Commands") { mdl_name = mdl_name.Substring(0, mdl_name.Length - 8); } } if (!this.Config.CaseSensitive) { mdl_name = mdl_name.ToLowerInvariant(); } cgbldr.WithName(mdl_name); foreach (var mi in ti.DeclaredMethods.Where(x => x.IsCommandCandidate(out _) && x.GetCustomAttribute <GroupCommandAttribute>() != null)) { cgbldr.WithOverload(new CommandOverloadBuilder(mi)); } break; case AliasesAttribute a: foreach (var xalias in a.Aliases) { cgbldr.WithAlias(this.Config.CaseSensitive ? xalias : xalias.ToLowerInvariant()); } break; case HiddenAttribute h: cgbldr.WithHiddenStatus(true); break; case DescriptionAttribute d: cgbldr.WithDescription(d.Description); break; case CheckBaseAttribute c: mdl_chks.Add(c); cgbldr.WithExecutionCheck(c); break; default: cgbldr.WithCustomAttribute(xa); break; } } if (!is_mdl) { cgbldr = null; } // candidate methods var ms = ti.DeclaredMethods; var cmds = new List <CommandBuilder>(); var cblds = new Dictionary <string, CommandBuilder>(); foreach (var m in ms) { if (!m.IsCommandCandidate(out _)) { continue; } var attrs = m.GetCustomAttributes(); var cattr = attrs.FirstOrDefault(xa => xa is CommandAttribute) as CommandAttribute; if (cattr == null) { continue; } var cname = cattr.Name; if (cname == null) { cname = m.Name; if (cname.EndsWith("Async") && cname != "Async") { cname = cname.Substring(0, cname.Length - 5); } } if (!this.Config.CaseSensitive) { cname = cname.ToLowerInvariant(); } if (!cblds.TryGetValue(cname, out var cmdbld)) { cblds.Add(cname, cmdbld = new CommandBuilder(module).WithName(cname)); if (!is_mdl) { if (currentParent != null) { currentParent.WithChild(cmdbld); } else { cmds.Add(cmdbld); } } else { cgbldr.WithChild(cmdbld); } } cmdbld.WithOverload(new CommandOverloadBuilder(m)); if (!is_mdl && mdl_chks.Any()) { foreach (var chk in mdl_chks) { cmdbld.WithExecutionCheck(chk); } } foreach (var xa in attrs) { switch (xa) { case AliasesAttribute a: foreach (var xalias in a.Aliases) { cmdbld.WithAlias(this.Config.CaseSensitive ? xalias : xalias.ToLowerInvariant()); } break; case CheckBaseAttribute p: cmdbld.WithExecutionCheck(p); break; case DescriptionAttribute d: cmdbld.WithDescription(d.Description); break; case HiddenAttribute h: cmdbld.WithHiddenStatus(true); break; default: cmdbld.WithCustomAttribute(xa); break; } } if (!is_mdl && mdl_hidden) { cmdbld.WithHiddenStatus(true); } } // candidate types var ts = ti.DeclaredNestedTypes .Where(xt => xt.IsModuleCandidateType() && xt.DeclaredConstructors.Any(xc => xc.IsPublic)); foreach (var xt in ts) { this.RegisterCommands(xt.AsType(), cgbldr, out var tcmds); if (is_mdl && tcmds != null) { foreach (var xtcmd in tcmds) { cgbldr.WithChild(xtcmd); } } else if (tcmds != null) { cmds.AddRange(tcmds); } } if (is_mdl && currentParent == null) { cmds.Add(cgbldr); } else if (is_mdl) { currentParent.WithChild(cgbldr); } commands = cmds; }