1import chalk from 'chalk'; 2import oraReal, { Ora } from 'ora'; 3 4// import * as Log from '../log'; 5import { env } from './env'; 6import { isInteractive } from './interactive'; 7 8const logReal = console.log; 9const infoReal = console.info; 10const warnReal = console.warn; 11const errorReal = console.error; 12 13const runningSpinners: oraReal.Ora[] = []; 14 15export function getAllSpinners() { 16 return runningSpinners; 17} 18 19/** 20 * A custom ora spinner that sends the stream to stdout in CI, non-TTY, or expo's non-interactive flag instead of stderr (the default). 21 * 22 * @param options 23 * @returns 24 */ 25export function ora(options?: oraReal.Options | string): oraReal.Ora { 26 const inputOptions = typeof options === 'string' ? { text: options } : options || {}; 27 const disabled = !isInteractive() || env.EXPO_DEBUG; 28 const spinner = oraReal({ 29 // Ensure our non-interactive mode emulates CI mode. 30 isEnabled: !disabled, 31 // In non-interactive mode, send the stream to stdout so it prevents looking like an error. 32 stream: disabled ? process.stdout : process.stderr, 33 ...inputOptions, 34 }); 35 36 const oraStart = spinner.start.bind(spinner); 37 const oraStop = spinner.stop.bind(spinner); 38 const oraStopAndPersist = spinner.stopAndPersist.bind(spinner); 39 40 const logWrap = (method: any, args: any[]): void => { 41 oraStop(); 42 method(...args); 43 spinner.start(); 44 }; 45 46 const wrapNativeLogs = (): void => { 47 console.log = (...args: any) => logWrap(logReal, args); 48 console.info = (...args: any) => logWrap(infoReal, args); 49 console.warn = (...args: any) => logWrap(warnReal, args); 50 console.error = (...args: any) => logWrap(errorReal, args); 51 52 runningSpinners.push(spinner); 53 }; 54 55 const resetNativeLogs = (): void => { 56 console.log = logReal; 57 console.info = infoReal; 58 console.warn = warnReal; 59 console.error = errorReal; 60 61 const index = runningSpinners.indexOf(spinner); 62 if (index >= 0) { 63 runningSpinners.splice(index, 1); 64 } 65 }; 66 67 spinner.start = (text): Ora => { 68 wrapNativeLogs(); 69 return oraStart(text); 70 }; 71 72 spinner.stopAndPersist = (options): Ora => { 73 const result = oraStopAndPersist(options); 74 resetNativeLogs(); 75 return result; 76 }; 77 78 spinner.stop = (): Ora => { 79 const result = oraStop(); 80 resetNativeLogs(); 81 return result; 82 }; 83 84 // Always make the central logging module aware of the current spinner 85 // Log.setSpinner(spinner); 86 87 return spinner; 88} 89 90/** 91 * Create a unified section spinner. 92 * 93 * @param title 94 * @returns 95 */ 96export function logNewSection(title: string) { 97 const spinner = ora(chalk.bold(title)); 98 // Prevent the spinner from clashing with debug logs 99 spinner.start(); 100 return spinner; 101} 102