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