1
1
import chalk from 'chalk' ;
2
2
import autoBind from 'auto-bind' ;
3
3
import { LogManager , Logger , TaskQueue , TaskQueueOptions , execScript } from '@bluecadet/launchpad-utils' ;
4
- import CommandHooks from './command-hooks.js' ;
4
+ import CommandHooks , { ExecHook } from './command-hooks.js' ;
5
5
6
6
export class CommandOptions {
7
7
constructor ( {
@@ -16,23 +16,23 @@ export class CommandOptions {
16
16
17
17
export class CommandCenter {
18
18
/** @type {CommandOptions } */
19
- _config = { } ;
19
+ _config ;
20
20
21
21
/** @type {Logger } */
22
- _logger = null ;
22
+ _logger ;
23
23
24
24
/** @type {Map<string, Command> } */
25
25
_commands = new Map ( ) ;
26
26
27
27
/** @type {TaskQueue } */
28
- _tasks = null ;
28
+ _tasks ;
29
29
30
30
/**
31
31
*
32
- * @param {CommandOptions|Object } config
33
- * @param {* } logger
32
+ * @param {CommandOptions|Object } [ config]
33
+ * @param {Logger } [ logger]
34
34
*/
35
- constructor ( config = null , logger = null ) {
35
+ constructor ( config , logger ) {
36
36
autoBind ( this ) ;
37
37
this . _config = new CommandOptions ( config ) ;
38
38
this . _logger = logger || LogManager . getInstance ( ) . getLogger ( ) ;
@@ -54,15 +54,17 @@ export class CommandCenter {
54
54
/**
55
55
*
56
56
* @param {string } commandName The name of the command to run
57
- * @returns {Promise } The promise returned by the command function
57
+ * @param {unknown[] } args
58
+ * @returns {Promise<void | null> } The promise returned by the command function
58
59
*/
59
60
async run ( commandName , ...args ) {
60
- if ( ! this . _commands . has ( commandName ) ) {
61
+ const command = this . _commands . get ( commandName ) ;
62
+
63
+ if ( ! command ) {
61
64
return Promise . reject ( new Error ( `Command not found: '${ commandName } '` ) ) ;
62
65
}
63
66
64
67
this . _logger . info ( `Running command: ${ chalk . blue ( commandName ) } ` ) ;
65
- const command = this . _commands . get ( commandName ) ;
66
68
67
69
if ( command . queued ) {
68
70
return this . _tasks . add ( command . run , command . name , ...args ) ;
@@ -72,22 +74,27 @@ export class CommandCenter {
72
74
}
73
75
74
76
/**
75
- * @param {CommandHooks } hooks
77
+ * @param {CommandHooks } commandHooks
76
78
*/
77
79
addCommandHooks ( commandHooks ) {
80
+ /**
81
+ *
82
+ * @param {ExecHook[] } hooks
83
+ * @param {boolean } isPre
84
+ */
78
85
const add = ( hooks , isPre ) => {
79
86
const label = isPre ? 'pre' : 'post' ;
80
87
for ( const hook of hooks ) {
81
88
try {
82
89
this . _logger . info ( `Adding ${ label } -hook for ${ chalk . blue ( hook . command ) } : '${ hook . script } '` ) ;
83
90
const fn = async ( ) => {
84
91
this . _logger . info ( `Running ${ chalk . magenta ( `${ label } -hook` ) } for ${ chalk . blue ( hook . command ) } : '${ hook . script } '` ) ;
85
- return execScript ( hook . script , null , this . _logger ) ;
92
+ await execScript ( hook . script , undefined , this . _logger ) ;
86
93
} ;
87
94
this . addHook ( hook . command , isPre ? fn : null , isPre ? null : fn ) ;
88
95
} catch ( err ) {
89
96
this . _logger . error ( `Can't add ${ label } -hook '${ hook . script } ' for '${ chalk . blue ( hook . command ) } ':` , err ) ;
90
- execScript ( hook . command , null , this . _logger ) ;
97
+ execScript ( hook . command , undefined , this . _logger ) ;
91
98
}
92
99
}
93
100
} ;
@@ -98,14 +105,16 @@ export class CommandCenter {
98
105
/**
99
106
*
100
107
* @param {string } commandName
101
- * @param {function(): Promise } before Called before the command is run
102
- * @param {function(): Promise } after Called after the command was run
108
+ * @param {(() => Promise<void>)? } before Called before the command is run
109
+ * @param {(() => Promise<void>)? } after Called after the command was run
103
110
*/
104
111
addHook ( commandName , before = null , after = null ) {
105
- if ( ! this . _commands . has ( commandName ) ) {
112
+ const command = this . _commands . get ( commandName ) ;
113
+
114
+ if ( ! command ) {
106
115
throw new Error ( `Command not found: '${ commandName } '` ) ;
107
116
}
108
- const command = this . _commands . get ( commandName ) ;
117
+
109
118
if ( before ) {
110
119
command . preHooks . push ( before ) ;
111
120
this . _logger . debug ( `Added pre-hook for: ${ chalk . blue ( commandName ) } ` ) ;
@@ -117,14 +126,25 @@ export class CommandCenter {
117
126
}
118
127
}
119
128
129
+ /**
130
+ * @template {(...args: any[]) => Promise<unknown>} [F=(...args: any[]) => Promise<void>]
131
+ */
120
132
export class Command {
133
+ /**
134
+ * @param {object } options
135
+ * @param {string } options.name
136
+ * @param {F } options.callback
137
+ * @param {string } [options.help]
138
+ * @param {boolean } [options.queued]
139
+ * @param {Logger | null } [options.logger]
140
+ */
121
141
constructor ( {
122
142
name,
123
143
callback,
124
144
help = '' ,
125
145
queued = true ,
126
146
logger = null
127
- } = { } ) {
147
+ } ) {
128
148
autoBind ( this ) ;
129
149
/**
130
150
* The name of the command used for running.
@@ -133,7 +153,7 @@ export class Command {
133
153
this . name = name ;
134
154
/**
135
155
* The callback to trigger. Will receives args passed via run().
136
- * @type {function():Promise }
156
+ * @type {F }
137
157
*/
138
158
this . callback = callback ;
139
159
/**
@@ -148,24 +168,24 @@ export class Command {
148
168
this . queued = queued ;
149
169
/**
150
170
* Callbacks that will be triggered before the command is executed.
151
- * @type {Array<function(): Promise> }
171
+ * @type {Array<(...args: Parameters<F>)=> Promise<void> > }
152
172
*/
153
173
this . preHooks = [ ] ;
154
174
/**
155
175
* Callbacks that will be triggered after the command was executed.
156
- * @type {Array<function(): Promise> }
176
+ * @type {Array<(...args: Parameters<F>)=> Promise<void> > }
157
177
*/
158
178
this . postHooks = [ ] ;
159
179
/**
160
- * @type {Logger }
180
+ * @type {Logger | null }
161
181
*/
162
182
this . logger = logger ;
163
183
}
164
184
165
185
/**
166
186
* Runs a command with optional pre- and post-command hooks.
167
- * @param {...any } args
168
- * @returns {* } Results of this command's callback function, if any
187
+ * @param {Parameters<F> } args
188
+ * @returns {Promise<ReturnType<F> | null> } Results of this command's callback function, if any
169
189
*/
170
190
async run ( ...args ) {
171
191
const logger = this . logger || console ;
@@ -176,8 +196,12 @@ export class Command {
176
196
logger . error ( `Could not run pre-hook for command ${ chalk . blue ( this . name ) } :` , err ) ;
177
197
}
178
198
}
199
+ /**
200
+ * @type {ReturnType<F> | null }
201
+ */
179
202
let result = null ;
180
203
try {
204
+ // @ts -expect-error - no clue why TS is complaining here...
181
205
result = await this . callback ( ...args ) ;
182
206
} catch ( err ) {
183
207
logger . error ( `Could not run command ${ chalk . blue ( this . name ) } :` , err ) ;
0 commit comments