1
- import { Flags , CliUx } from '@oclif/core' ;
1
+ import { Flags } from '@oclif/core' ;
2
2
import Command from '../../base' ;
3
3
// eslint-disable-next-line
4
4
// @ts -ignore
@@ -13,11 +13,8 @@ import { ValidationError } from '../../errors/validation-error';
13
13
import { GeneratorError } from '../../errors/generator-error' ;
14
14
import { Parser } from '@asyncapi/parser' ;
15
15
import type { Example } from '@oclif/core/lib/interfaces' ;
16
-
17
- const red = ( text : string ) => `\x1b[31m${ text } \x1b[0m` ;
18
- const magenta = ( text : string ) => `\x1b[35m${ text } \x1b[0m` ;
19
- const yellow = ( text : string ) => `\x1b[33m${ text } \x1b[0m` ;
20
- const green = ( text : string ) => `\x1b[32m${ text } \x1b[0m` ;
16
+ import { intro , isCancel , spinner , text } from '@clack/prompts' ;
17
+ import { inverse , yellow , magenta , green , red } from 'picocolors' ;
21
18
22
19
interface IMapBaseUrlToFlag {
23
20
url : string ,
@@ -68,6 +65,11 @@ export default class Template extends Command {
68
65
description : 'Disable a specific hook type or hooks from a given hook type' ,
69
66
multiple : true
70
67
} ) ,
68
+ 'no-interactive' : Flags . boolean ( {
69
+ description : 'Disable interactive mode and run with the provided flags.' ,
70
+ required : false ,
71
+ default : false ,
72
+ } ) ,
71
73
install : Flags . boolean ( {
72
74
char : 'i' ,
73
75
default : false ,
@@ -103,18 +105,27 @@ export default class Template extends Command {
103
105
} ;
104
106
105
107
static args = [
106
- { name : 'asyncapi' , description : '- Local path, url or context-name pointing to AsyncAPI file' , required : true } ,
107
- { name : 'template' , description : '- Name of the generator template like for example @asyncapi/html-template or https://github.com/asyncapi/html-template' , required : true }
108
+ { name : 'asyncapi' , description : '- Local path, url or context-name pointing to AsyncAPI file' } ,
109
+ { name : 'template' , description : '- Name of the generator template like for example @asyncapi/html-template or https://github.com/asyncapi/html-template' } ,
108
110
] ;
109
111
110
112
parser = new Parser ( ) ;
111
113
112
114
async run ( ) {
113
115
const { args, flags } = await this . parse ( Template ) ; // NOSONAR
116
+ const interactive = ! flags [ 'no-interactive' ] ;
117
+
118
+ let { asyncapi, template } = args ;
119
+ let output = flags . output as string ;
120
+ if ( interactive ) {
121
+ intro ( inverse ( 'AsyncAPI Generator' ) ) ;
122
+
123
+ const parsedArgs = await this . parseArgs ( args , output ) ;
124
+ asyncapi = parsedArgs . asyncapi ;
125
+ template = parsedArgs . template ;
126
+ output = parsedArgs . output ;
127
+ }
114
128
115
- const asyncapi = args [ 'asyncapi' ] ;
116
- const template = args [ 'template' ] ;
117
- const output = flags . output || process . cwd ( ) ;
118
129
const parsedFlags = this . parseFlags ( flags [ 'disable-hook' ] , flags [ 'param' ] , flags [ 'map-base-url' ] ) ;
119
130
const options = {
120
131
forceWrite : flags [ 'force-write' ] ,
@@ -142,13 +153,66 @@ export default class Template extends Command {
142
153
this . error ( `${ template } template does not support AsyncAPI v3 documents, please checkout ${ v3IssueLink } ` ) ;
143
154
}
144
155
}
145
- await this . generate ( asyncapi , template , output , options , genOption ) ;
156
+ await this . generate ( asyncapi , template , output , options , genOption , interactive ) ;
146
157
if ( watchTemplate ) {
147
- const watcherHandler = this . watcherHandler ( asyncapi , template , output , options , genOption ) ;
158
+ const watcherHandler = this . watcherHandler ( asyncapi , template , output , options , genOption , interactive ) ;
148
159
await this . runWatchMode ( asyncapi , template , output , watcherHandler ) ;
149
160
}
150
161
}
151
162
163
+ private async parseArgs ( args : Record < string , any > , output ?: string ) : Promise < { asyncapi : string ; template : string ; output : string ; } > {
164
+ let asyncapi = args [ 'asyncapi' ] ;
165
+ let template = args [ 'template' ] ;
166
+ const cancellationMessage = 'Operation cancelled' ;
167
+
168
+ if ( ! asyncapi ) {
169
+ asyncapi = await text ( {
170
+ message : 'Please provide the path to the AsyncAPI document' ,
171
+ placeholder : 'asyncapi.yaml' ,
172
+ defaultValue : 'asyncapi.yaml' ,
173
+ validate ( value : string ) {
174
+ if ( ! value ) {
175
+ return 'The path to the AsyncAPI document is required' ;
176
+ } else if ( ! fs . existsSync ( value ) ) {
177
+ return 'The file does not exist' ;
178
+ }
179
+ }
180
+ } ) ;
181
+ }
182
+
183
+ if ( isCancel ( asyncapi ) ) {
184
+ this . error ( cancellationMessage , { exit : 1 } ) ;
185
+ }
186
+
187
+ if ( ! template ) {
188
+ template = await text ( {
189
+ message : 'Please provide the name of the generator template' ,
190
+ placeholder : '@asyncapi/html-template' ,
191
+ defaultValue : '@asyncapi/html-template' ,
192
+ } ) ;
193
+ }
194
+
195
+ if ( ! output ) {
196
+ output = await text ( {
197
+ message : 'Please provide the output directory' ,
198
+ placeholder : './docs' ,
199
+ validate ( value : string ) {
200
+ if ( ! value ) {
201
+ return 'The output directory is required' ;
202
+ } else if ( typeof value !== 'string' ) {
203
+ return 'The output directory must be a string' ;
204
+ }
205
+ }
206
+ } ) as string ;
207
+ }
208
+
209
+ if ( isCancel ( output ) || isCancel ( template ) ) {
210
+ this . error ( cancellationMessage , { exit : 1 } ) ;
211
+ }
212
+
213
+ return { asyncapi, template, output } ;
214
+ }
215
+
152
216
private parseFlags ( disableHooks ?: string [ ] , params ?: string [ ] , mapBaseUrl ?: string ) : ParsedFlags {
153
217
return {
154
218
params : this . paramParser ( params ) ,
@@ -204,7 +268,7 @@ export default class Template extends Command {
204
268
return mapBaseURLToFolder ;
205
269
}
206
270
207
- private async generate ( asyncapi : string | undefined , template : string , output : string , options : any , genOption : any ) {
271
+ private async generate ( asyncapi : string | undefined , template : string , output : string , options : any , genOption : any , interactive = true ) {
208
272
let specification : Specification ;
209
273
try {
210
274
specification = await load ( asyncapi ) ;
@@ -218,16 +282,15 @@ export default class Template extends Command {
218
282
) ;
219
283
}
220
284
const generator = new AsyncAPIGenerator ( template , output || path . resolve ( os . tmpdir ( ) , 'asyncapi-generator' ) , options ) ;
221
-
222
- CliUx . ux . action . start ( 'Generation in progress. Keep calm and wait a bit' ) ;
285
+ const s = interactive ? spinner ( ) : { start : ( ) => null , stop : ( string : string ) => console . log ( string ) } ;
286
+ s . start ( 'Generation in progress. Keep calm and wait a bit' ) ;
223
287
try {
224
288
await generator . generateFromString ( specification . text ( ) , genOption ) ;
225
- CliUx . ux . action . stop ( ) ;
226
289
} catch ( err : any ) {
227
- CliUx . ux . action . stop ( 'done\n ' ) ;
290
+ s . stop ( 'Generation failed ' ) ;
228
291
throw new GeneratorError ( err ) ;
229
292
}
230
- console . log ( `${ yellow ( 'Check out your shiny new generated files at ' ) + magenta ( output ) + yellow ( '.' ) } \n` ) ;
293
+ s . stop ( `${ yellow ( 'Check out your shiny new generated files at ' ) + magenta ( output ) + yellow ( '.' ) } \n` ) ;
231
294
}
232
295
233
296
private async runWatchMode ( asyncapi : string | undefined , template : string , output : string , watchHandler : ReturnType < typeof this . watcherHandler > ) {
@@ -270,7 +333,7 @@ export default class Template extends Command {
270
333
} ) ;
271
334
}
272
335
273
- private watcherHandler ( asyncapi : string , template : string , output : string , options : Record < string , any > , genOption : any ) : ( changedFiles : Record < string , any > ) => Promise < void > {
336
+ private watcherHandler ( asyncapi : string , template : string , output : string , options : Record < string , any > , genOption : any , interactive : boolean ) : ( changedFiles : Record < string , any > ) => Promise < void > {
274
337
return async ( changedFiles : Record < string , any > ) : Promise < void > => {
275
338
console . clear ( ) ;
276
339
console . log ( '[WATCHER] Change detected' ) ;
@@ -292,7 +355,7 @@ export default class Template extends Command {
292
355
this . log ( `\t${ magenta ( value . path ) } was ${ eventText } ` ) ;
293
356
}
294
357
try {
295
- await this . generate ( asyncapi , template , output , options , genOption ) ;
358
+ await this . generate ( asyncapi , template , output , options , genOption , interactive ) ;
296
359
} catch ( err : any ) {
297
360
throw new GeneratorError ( err ) ;
298
361
}
0 commit comments