1import chalk from 'chalk'; 2import { watchFile } from 'fs'; 3import path from 'path'; 4import resolveFrom from 'resolve-from'; 5 6import * as Log from '../log'; 7import { memoize } from './fn'; 8 9/** Observes and reports file changes. */ 10export class FileNotifier { 11 constructor( 12 /** Project root to resolve the module IDs relative to. */ 13 private projectRoot: string, 14 /** List of module IDs sorted by priority. Only the first file that exists will be observed. */ 15 private moduleIds: string[], 16 private settings: { 17 /** An additional warning message to add to the notice. */ 18 additionalWarning?: string; 19 } = {} 20 ) {} 21 22 /** Get the file in the project. */ 23 private resolveFilePath(): string | null { 24 for (const moduleId of this.moduleIds) { 25 const filePath = resolveFrom.silent(this.projectRoot, moduleId); 26 if (filePath) { 27 return filePath; 28 } 29 } 30 return null; 31 } 32 33 public startObserving() { 34 const configPath = this.resolveFilePath(); 35 if (configPath) { 36 return this.watchFile(configPath); 37 } 38 return configPath; 39 } 40 41 /** Watch the file and warn to reload the CLI if it changes. */ 42 public watchFile = memoize(this.startWatchingFile.bind(this)); 43 44 private startWatchingFile(filePath: string): string { 45 const configName = path.relative(this.projectRoot, filePath); 46 watchFile(filePath, (cur: any, prev: any) => { 47 if (prev.size || cur.size) { 48 Log.log( 49 `\u203A Detected a change in ${chalk.bold( 50 configName 51 )}. Restart the server to see the new results.` + (this.settings.additionalWarning || '') 52 ); 53 } 54 }); 55 return filePath; 56 } 57} 58