2222 */
2323class CommandRouter implements Listener
2424{
25- /** @var array<string, Listener> */
26- private array $ routes ;
25+ private Listener $ default ;
2726 private string $ description ;
2827 private int $ maxLevels ;
28+ /** @var array<string, Listener> */
29+ private array $ routes ;
2930
3031 public static function new (): self
3132 {
@@ -37,21 +38,37 @@ public function __construct(array $routes = [])
3738 $ this ->routes = [];
3839 $ this ->description = '' ;
3940 $ this ->maxLevels = 1 ;
40- $ this ->add ('list ' , Closure::fromCallable ([$ this , 'listSubCommands ' ]));
41+ $ this ->add ('help ' , Closure::fromCallable ([$ this , 'showHelp ' ]));
4142 foreach ($ routes as $ subCommand => $ listener ) {
4243 $ this ->add ($ subCommand , $ listener );
4344 }
4445 }
4546
4647 /**
4748 * @param string $subCommand
48- * @param Listener|callable|class-string $listener
49+ * @param Listener|callable(Context): void |class-string $listener
4950 * @return $this
5051 */
5152 public function add (string $ subCommand , $ listener ): self
5253 {
53- $ this ->routes [$ subCommand ] = Coerce::listener ($ listener );
54- $ this ->maxLevels = max ($ this ->maxLevels , count (explode (' ' , $ subCommand )));
54+ $ listener = Coerce::listener ($ listener );
55+ if ($ subCommand === '* ' ) {
56+ $ this ->default = $ listener ;
57+ } else {
58+ $ this ->routes [$ subCommand ] = $ listener ;
59+ $ this ->maxLevels = max ($ this ->maxLevels , count (explode (' ' , $ subCommand )));
60+ }
61+
62+ return $ this ;
63+ }
64+
65+ /**
66+ * @param Listener|callable(Context): void|class-string $listener
67+ * @return $this
68+ */
69+ public function withDefault ($ listener ): self
70+ {
71+ $ this ->default = Coerce::listener ($ listener );
5572
5673 return $ this ;
5774 }
@@ -60,7 +77,7 @@ public function add(string $subCommand, $listener): self
6077 * @param string $description
6178 * @return self
6279 */
63- public function description (string $ description ): self
80+ public function withDescription (string $ description ): self
6481 {
6582 $ this ->description = $ description ;
6683
@@ -85,31 +102,35 @@ public function handle(Context $context): void
85102 array_pop ($ nameArgs );
86103 }
87104
88- $ context ->logger ()->debug ('CommandRouter could not find sub-command; routing to "list" instead ' );
89- $ this ->listSubCommands ($ context );
105+ if ($ this ->default ) {
106+ $ this ->default ->handle ($ context );
107+ } else {
108+ $ this ->showHelp ($ context );
109+ }
90110 }
91111
92- private function listSubCommands (Context $ ctx ): void
112+ private function showHelp (Context $ context ): void
93113 {
94- $ cmd = $ ctx ->payload ()->get ('command ' );
95- $ fmt = $ ctx ->fmt ();
96- $ msg = $ ctx ->blocks ()->message ()->header ("The {$ cmd } Command " );
114+ $ cmd = $ context ->payload ()->get ('command ' );
115+ $ fmt = $ context ->fmt ();
116+ $ msg = $ context ->blocks ()->message ();
117+
118+ $ msg ->header ("The {$ cmd } Command " );
97119 if ($ this ->description ) {
98120 $ msg ->text ($ this ->description );
99121 }
100122
101123 $ routes = array_keys ($ this ->routes );
102124 natsort ($ routes );
103-
104125 $ msg ->newSection ()->mrkdwnText ($ fmt ->lines ([
105- '*Available commands*: ' ,
126+ '*Available sub- commands*: ' ,
106127 $ fmt ->bulletedList (array_map (fn (string $ subCommand ) => $ fmt ->code ("{$ cmd } {$ subCommand }" ), $ routes ))
107128 ]));
108129
109- if ($ ctx ->isAcknowledged ()) {
110- $ ctx ->respond ($ msg );
130+ if ($ context ->isAcknowledged ()) {
131+ $ context ->respond ($ msg );
111132 } else {
112- $ ctx ->ack ($ msg );
133+ $ context ->ack ($ msg );
113134 }
114135 }
115136}
0 commit comments