Skip to content

Commit 0bc744b

Browse files
authored
GH-173 Add @rootroute annotation. Add an option to create all commands in one class. Add unit test for @rootroute annotation. (#174)
* GH-173 Add @rootroute annotation. Add an option to create all commands in one class. Add unit test for @rootroute annotation. * Fix unit test.
1 parent a002751 commit 0bc744b

File tree

7 files changed

+125
-17
lines changed

7 files changed

+125
-17
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dev.rollczi.litecommands.command.root;
2+
3+
import dev.rollczi.litecommands.factory.FactoryAnnotationResolver;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Target({ ElementType.TYPE, ElementType.METHOD})
11+
@Retention(RetentionPolicy.RUNTIME)
12+
public @interface RootRoute {
13+
14+
FactoryAnnotationResolver<RootRoute> RESOLVER = new RootRouteAnnotationResolver();
15+
16+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dev.rollczi.litecommands.command.root;
2+
3+
import dev.rollczi.litecommands.factory.CommandState;
4+
import dev.rollczi.litecommands.factory.FactoryAnnotationResolver;
5+
import dev.rollczi.litecommands.shared.StringUtils;
6+
import panda.std.Option;
7+
8+
class RootRouteAnnotationResolver implements FactoryAnnotationResolver<RootRoute> {
9+
10+
@Override
11+
public Option<CommandState> resolve(RootRoute annotation, CommandState commandState) {
12+
return Option.of(commandState
13+
.name(StringUtils.EMPTY)
14+
.cancel(false)
15+
);
16+
}
17+
18+
@Override
19+
public Class<RootRoute> getAnnotationClass() {
20+
return RootRoute.class;
21+
}
22+
23+
}

litecommands-core/src/main/java/dev/rollczi/litecommands/factory/CommandStateFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import panda.std.Option;
55

66
import java.lang.annotation.Annotation;
7+
import java.util.List;
78

89
public interface CommandStateFactory<SENDER> {
910

10-
Option<CommandSection<SENDER>> create(Object instance);
11+
Option<List<CommandSection<SENDER>>> create(Object instance);
1112

1213
<A extends Annotation> void annotationResolver(FactoryAnnotationResolver<A> resolver);
1314

litecommands-core/src/main/java/dev/rollczi/litecommands/implementation/LiteCommandFactory.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import java.lang.reflect.Method;
2323
import java.lang.reflect.Parameter;
2424
import java.util.ArrayList;
25+
import java.util.Collections;
2526
import java.util.HashSet;
2627
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Set;
30+
import java.util.stream.Collectors;
2931

3032
class LiteCommandFactory<SENDER> implements CommandStateFactory<SENDER> {
3133

@@ -43,16 +45,31 @@ class LiteCommandFactory<SENDER> implements CommandStateFactory<SENDER> {
4345
}
4446

4547
@Override
46-
public Option<CommandSection<SENDER>> create(Object instance) {
48+
public Option<List<CommandSection<SENDER>>> create(Object instance) {
4749
CommandState state = this.createState(instance);
4850

49-
if (state.getName() == null || state.getName().isEmpty() || state.isCanceled()) {
51+
if (state.getName() == null || state.isCanceled()) {
5052
return Option.none();
5153
}
5254

5355
CommandSection<SENDER> section = this.stateToSection(state, instance);
56+
List<CommandSection<SENDER>> sections = this.unpackEmptySection(section);
5457

55-
return Option.of(section);
58+
return Option.of(sections);
59+
}
60+
61+
private List<CommandSection<SENDER>> unpackEmptySection(CommandSection<SENDER> section) {
62+
if (section.getName().isEmpty()) {
63+
if (!section.executors().isEmpty()) {
64+
throw new IllegalStateException("Empty section cannot have executors without name");
65+
}
66+
67+
return section.childrenSection().stream()
68+
.flatMap(child -> this.unpackEmptySection(child).stream())
69+
.collect(Collectors.toList());
70+
}
71+
72+
return Collections.singletonList(section);
5673
}
5774

5875
@Override
@@ -131,9 +148,10 @@ private CommandSection<SENDER> stateToSection(CommandState state, Object instanc
131148
section = this.resolveStateOnSection(section, instance, state);
132149

133150
PandaStream.of(instance.getClass().getDeclaredClasses())
134-
.mapOpt(type -> Option.supplyThrowing(InjectException.class, () -> injector.createInstance(type)))
135-
.mapOpt(this::create)
136-
.forEach(section::childSection);
151+
.mapOpt(type -> Option.supplyThrowing(InjectException.class, () -> this.injector.createInstance(type)))
152+
.mapOpt(this::create)
153+
.flatMap(commandSections -> commandSections)
154+
.forEach(section::childSection);
137155

138156
return section;
139157
}

litecommands-core/src/main/java/dev/rollczi/litecommands/implementation/LiteCommandsBuilderImpl.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,24 +269,26 @@ public LiteCommands<SENDER> register() {
269269

270270
List<CommandSection<SENDER>> commandSections = new ArrayList<>();
271271

272-
root:
273272
for (Object instance : this.commandsInstances) {
274-
Option<CommandSection<SENDER>> option = this.commandStateFactory.create(instance);
273+
Option<List<CommandSection<SENDER>>> listOption = this.commandStateFactory.create(instance);
275274

276-
if (option.isEmpty()) {
275+
if (listOption.isEmpty()) {
277276
continue;
278277
}
279278

280-
CommandSection<SENDER> currentCommand = option.get();
279+
List<CommandSection<SENDER>> currentCommands = listOption.get();
281280

282-
for (CommandSection<SENDER> commandSection : commandSections) {
283-
if (commandSection.isSimilar(currentCommand.getName())) {
284-
commandSection.mergeSection(currentCommand);
285-
continue root;
281+
root:
282+
for (CommandSection<SENDER> currentCommand : currentCommands) {
283+
for (CommandSection<SENDER> commandSection : commandSections) {
284+
if (commandSection.isSimilar(currentCommand.getName())) {
285+
commandSection.mergeSection(currentCommand);
286+
continue root;
287+
}
286288
}
287-
}
288289

289-
commandSections.add(currentCommand);
290+
commandSections.add(currentCommand);
291+
}
290292
}
291293

292294
for (CommandSection<SENDER> commandSection : commandSections) {

litecommands-core/src/main/java/dev/rollczi/litecommands/implementation/LiteFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import dev.rollczi.litecommands.command.permission.ExecutedPermission;
5151
import dev.rollczi.litecommands.command.permission.Permission;
5252
import dev.rollczi.litecommands.command.permission.RequiredPermissions;
53+
import dev.rollczi.litecommands.command.root.RootRoute;
5354
import dev.rollczi.litecommands.command.route.Route;
5455
import dev.rollczi.litecommands.command.section.Section;
5556
import dev.rollczi.litecommands.handle.Redirector;
@@ -95,6 +96,7 @@ public static <SENDER> LiteCommandsBuilder<SENDER> builder(Class<SENDER> senderT
9596
.configureFactory(factory -> {
9697
factory.annotationResolver(Section.RESOLVER);
9798
factory.annotationResolver(Route.RESOLVER);
99+
factory.annotationResolver(RootRoute.RESOLVER);
98100
factory.annotationResolver(Execute.RESOLVER);
99101
factory.annotationResolver(Permission.RESOLVER);
100102
factory.annotationResolver(Permission.REPEATABLE_RESOLVER);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dev.rollczi.litecommands.command.root;
2+
3+
import dev.rollczi.litecommands.command.execute.Execute;
4+
import dev.rollczi.litecommands.command.permission.Permission;
5+
import dev.rollczi.litecommands.command.permission.RequiredPermissions;
6+
import dev.rollczi.litecommands.test.TestFactory;
7+
import dev.rollczi.litecommands.test.TestPlatform;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.Arrays;
11+
12+
import static dev.rollczi.litecommands.test.Assert.assertCollection;
13+
14+
class TestRootRouteCommand {
15+
16+
TestPlatform platform = TestFactory.withCommands(RootCommands.class);
17+
18+
@RootRoute
19+
static class RootCommands {
20+
@Execute(route = "msg")
21+
String msg() {
22+
return "msg";
23+
}
24+
25+
@Execute(route = "reply", aliases = {"r"})
26+
@Permission("reply")
27+
String reply() {
28+
return "reply";
29+
}
30+
}
31+
32+
@Test
33+
void testSimpleClassCommands() {
34+
this.platform.execute("msg")
35+
.assertSuccess()
36+
.assertResult("msg");
37+
38+
RequiredPermissions permissions = this.platform.execute("reply")
39+
.assertInvalid()
40+
.assertResultIs(RequiredPermissions.class);
41+
42+
assertCollection(Arrays.asList("reply"), permissions.getPermissions());
43+
}
44+
45+
46+
}

0 commit comments

Comments
 (0)