/
Watcher.ts
132 lines (115 loc) · 4.1 KB
/
Watcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import Chokidar, { FSWatcher } from "chokidar";
import path from "path";
import {
Config,
WatcherEvent,
WatcherEvents,
WatcherListeners
} from "../../interfaces";
import Provider from "../higher-order/Provider";
import Thread from "./Thread";
import { generateBasePathRelativeToRoot } from "../../utils";
/**
* The base watcher class, that handles all file watches and fires events accordingly.
* @extends Provider
* @category Core
*/
export default class Watcher extends Provider {
/**
* The paths generated by this `Watcher` instance, using the config.
*/
private paths: string | string[];
/**
* The root path generated by this `Watcher` instance, using the config.
*/
private root: string;
/**
* The instance of the `chokidar` watcher that powers this wrapper class.
*/
private instance: FSWatcher;
/**
* The instance of `Thread` which manages the execution of commands on firing of watcher event.
*/
private thread: Thread;
/**
* The list of handlers attached to events in this instance. Handlers can be attached to the `onBeforeStart`, `onStart`, `onBeforeChange`, `onChange`, `onBeforeStop` or `onStop` events.
*/
private listeners: WatcherListeners;
/**
* Creates an instance of the `Watcher`.
* @param {Config} config The base configuration for the watcher.
* @param {WatcherListeners} [listeners] Optional listeners than can be passed to run custom functions before or after emitted events.
*/
constructor(config: Config, listeners: WatcherListeners) {
super(config);
this.listeners = listeners;
const { paths, root, ignored = undefined } = this.config;
this.root = path.join(process.cwd(), root);
this.paths = generateBasePathRelativeToRoot(this.root, paths);
this.log.debug("Generated paths for watching", this.paths);
/**
* The raw chokidar instance which watches for changes and fires events.
*/
try {
this.instance = Chokidar.watch(this.paths, {
awaitWriteFinish: {
stabilityThreshold: this.config.buffer,
pollInterval: Math.round(this.config.buffer * 0.5)
},
ignored,
persistent: true,
ignoreInitial: true
});
} catch (error) {
throw error;
}
/**
* Start an instance of process handler, which manages the spawned process.
*/
this.thread = new Thread(this.config);
this.bindWatcherEvents();
}
/**
* Bind all watcher events to the instance.
*/
private async bindWatcherEvents(): Promise<void> {
this.instance.on("ready", async () => {
await this.thread.start(this.root);
console.log("");
});
this.instance.on("all", async (event, file) => {
console.log("");
await this.thread.restart(this.root);
this.log.debug(
"EVENT:",
event,
"| FILE:",
path.resolve(this.root, file)
);
console.log("");
});
this.instance.on("error", async error => {
this.log.fatal(error);
});
}
/**
* Allows attaching a handler to an watcher event. Does not attach event if `event` is not valid.
* @param {WatcherEvent} event The event to fire this function for. Possible options are `onBeforeStart`, `onStart`, `onBeforeChange`, `onChange`, `onBeforeStop` and `onStop`.
* @param {function} eventHandler The event handler function. Receives
*/
public on(event: WatcherEvent, eventHandler: Function): void {
if (!WatcherEvents.hasOwnProperty(event)) {
this.log.warn(
`Event '${event}' is not valid. Handler not attached.`
);
} else {
this.listeners[event] = eventHandler;
}
}
/**
* Returns the instance of the internal watcher.
*/
public getInstance(): FSWatcher {
return this.instance;
}
}