11'use strict'
22
3- /* eslint-disable no-console */
4-
53const { execSync, spawnSync } = require ( 'child_process' )
64
7- // Helpers for colored output.
8- const log = ( ...msgs ) => msgs . forEach ( msg => console . log ( msg ) )
9- const success = ( ...msgs ) => msgs . forEach ( msg => console . log ( `\x1b[32m${ msg } \x1b[0m` ) )
10- const error = ( ...msgs ) => msgs . forEach ( msg => console . log ( `\x1b[31m${ msg } \x1b[0m` ) )
11- const whisper = ( ...msgs ) => msgs . forEach ( msg => console . log ( `\x1b[90m${ msg } \x1b[0m` ) )
5+ const { params, flags } = parse ( )
126
13- // Helpers for exiting with a message.
14- const exit = ( ...msgs ) => log ( ...msgs ) || process . exit ( 0 )
15- const fatal = ( ...msgs ) => error ( ...msgs ) || process . exit ( 1 )
7+ const frames = [ '⠋' , '⠙' , '⠹' , '⠸' , '⠼' , '⠴' , '⠦' , '⠧' , '⠇' , '⠏' ]
168
17- // Output a command to the terminal and execute it.
18- function run ( cmd ) {
19- whisper ( `> ${ cmd } ` )
9+ const BOLD = '\x1b[1m'
10+ const CYAN = '\x1b[36m'
11+ const ERASE = '\x1b[0K'
12+ const GRAY = '\x1b[90m'
13+ const GREEN = '\x1b[32m'
14+ const PREVIOUS = '\x1b[1A'
15+ const RED = '\x1b[31m'
16+ const RESET = '\x1b[0m'
2017
21- const output = execSync ( cmd , { } ) . toString ( )
18+ const print = ( ...msgs ) => msgs . forEach ( msg => process . stdout . write ( msg ) )
19+ const log = ( ...msgs ) => msgs . forEach ( msg => print ( `${ msg } \n` ) )
20+ const fatal = ( ...msgs ) => log ( ...msgs ) || process . exit ( 1 )
2221
23- log ( output )
22+ let timer
23+ let current
24+
25+ // Output a command to the terminal and execute it.
26+ function run ( cmd ) {
27+ capture ( cmd )
2428}
2529
2630// Ask a question in terminal and return the response.
2731function prompt ( question ) {
28- process . stdout . write ( `${ question } ` )
32+ print ( `${ BOLD } ${ CYAN } ? ${ RESET } ${ BOLD } ${ question } ${ RESET } ` )
2933
3034 const child = spawnSync ( 'bash' , [ '-c' , 'read answer && echo $answer' ] , {
3135 stdio : [ 'inherit' ]
@@ -37,15 +41,110 @@ function prompt (question) {
3741// Ask whether to continue and otherwise exit the process.
3842function checkpoint ( question ) {
3943 const answer = prompt ( `${ question } [Y/n]` ) . trim ( )
44+ const prefix = `\r${ PREVIOUS } ${ BOLD } ${ CYAN } ?${ RESET } `
45+
46+ question = `${ BOLD } ${ question } ${ RESET } `
4047
4148 if ( answer && answer . toLowerCase ( ) !== 'y' ) {
49+ print ( `\r${ prefix } ${ question } ${ BOLD } ${ CYAN } No${ RESET } ${ ERASE } \n` )
4250 process . exit ( 0 )
51+ } else {
52+ print ( `\r${ prefix } ${ question } ${ BOLD } ${ CYAN } Yes${ RESET } ${ ERASE } \n` )
4353 }
4454}
4555
4656// Run a command and capture its output to return it to the caller.
4757function capture ( cmd ) {
48- return execSync ( cmd , { } ) . toString ( )
58+ if ( flags . debug ) {
59+ log ( `${ GRAY } > ${ cmd } ${ RESET } ` )
60+ }
61+
62+ const output = execSync ( cmd , { encoding : 'utf8' , stdio : 'pipe' } ) . toString ( ) . trim ( )
63+
64+ if ( flags . debug ) {
65+ log ( output )
66+ }
67+
68+ return output
69+ }
70+
71+ // Start an operation and show a spinner until it reports as passing or failing.
72+ function start ( title ) {
73+ current = title
74+
75+ spin ( 0 )
76+ }
77+
78+ // Show a spinner for the current operation.
79+ function spin ( index ) {
80+ if ( flags . debug ) return
81+
82+ print ( `\r${ CYAN } ${ frames [ index ] } ${ RESET } ${ BOLD } ${ current } ${ RESET } ` )
83+
84+ timer = setTimeout ( spin , 80 , index === frames . length - 1 ? 0 : index + 1 )
85+ }
86+
87+ // Finish the current operation as passing.
88+ function pass ( result ) {
89+ if ( ! current ) return
90+
91+ clearTimeout ( timer )
92+
93+ if ( ! flags . debug ) {
94+ print ( `\r${ GREEN } ✔${ RESET } ${ BOLD } ${ current } ${ RESET } ` )
95+
96+ if ( result ) {
97+ print ( `: ${ BOLD } ${ CYAN } ${ result } ${ RESET } ` )
98+ }
99+
100+ print ( '\n' )
101+ }
102+
103+ current = undefined
104+ }
105+
106+ // Finish the current operation as failing.
107+ function fail ( err ) {
108+ if ( ! current ) return
109+
110+ clearTimeout ( timer )
111+
112+ if ( ! flags . debug ) {
113+ print ( `\r${ RED } ✘${ RESET } ${ BOLD } ${ current } ${ RESET } \n` )
114+ }
115+
116+ current = undefined
117+
118+ throw err
119+ }
120+
121+ // Parse CLI arguments into parameters and flags.
122+ function parse ( ) {
123+ const args = process . argv . slice ( 2 )
124+ const params = [ ]
125+ const flags = { }
126+
127+ for ( const arg of args ) {
128+ if ( arg . startsWith ( '-' ) ) {
129+ const name = arg . replace ( / ^ - + / , '' )
130+ flags [ name ] = true
131+ } else {
132+ params . push ( arg )
133+ }
134+ }
135+
136+ return { params, flags }
49137}
50138
51- module . exports = { capture, checkpoint, error, exit, fatal, log, success, run, whisper }
139+ module . exports = {
140+ capture,
141+ checkpoint,
142+ fail,
143+ fatal,
144+ flags,
145+ log,
146+ params,
147+ pass,
148+ run,
149+ start
150+ }
0 commit comments