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  ) {}
17
18  /** Get the file in the project. */
19  private resolveFilePath(): string | undefined {
20    for (const moduleId of this.moduleIds) {
21      const filePath = resolveFrom.silent(this.projectRoot, moduleId);
22      if (filePath) {
23        return filePath;
24      }
25    }
26    return null;
27  }
28
29  public startObserving() {
30    const configPath = this.resolveFilePath();
31    if (configPath) {
32      return this.watchFile(configPath);
33    }
34    return configPath;
35  }
36
37  /** Watch the file and warn to reload the CLI if it changes. */
38  public watchFile = memoize(this.startWatchingFile.bind(this));
39
40  private startWatchingFile(filePath: string): string {
41    const configName = path.relative(this.projectRoot, filePath);
42    watchFile(filePath, (cur: any, prev: any) => {
43      if (prev.size || cur.size) {
44        Log.log(
45          `\u203A Detected a change in ${chalk.bold(
46            configName
47          )}. Restart the server to see the new results.`
48        );
49      }
50    });
51    return filePath;
52  }
53}
54