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