-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevents.ts
76 lines (65 loc) · 2.47 KB
/
events.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
import {watch} from "node:fs";
import {resolve} from "node:path";
import * as os from "node:os";
import {mergeMap, Observable, timer} from "rxjs";
import {map, mergeWith} from "rxjs/operators";
export type FileEvent = ReadyEvent | RenameEvent | ChangeEvent;
export interface ReadyEvent {
readonly event: "Ready";
readonly path: string;
readonly recursive: boolean;
}
export interface RenameEvent {
readonly event: "Rename";
readonly path: string | null;
}
export interface ChangeEvent {
readonly event: "Change";
readonly path: string | null;
}
export interface ObserveFileEventsOptions {
readonly path: string;
readonly recursive?: boolean | undefined;
}
const platform = os.platform();
export function observeFileEvents(
options: string | ObserveFileEventsOptions
): Observable<FileEvent> {
const path = resolve(typeof options === "string" ? options : options.path);
const recursive = typeof options === "object" ? (options.recursive ?? false) : false;
const ready = {event: "Ready", path, recursive} as const;
const events = new Observable<FileEvent>(subscriber => {
const abortController = new AbortController();
const watcher = watch(path, {signal: abortController.signal, recursive}, (event, path) => {
if (event === "rename") {
subscriber.next({event: "Rename", path} as const);
} else if (event === "change") {
subscriber.next({event: "Change", path} as const);
}
});
// On Windows and Linux, the watcher is ready as soon as fs.watch returns.
if (platform === "win32" || platform === "linux") {
subscriber.next(ready);
}
watcher.addListener("error", error => void subscriber.error(error));
return () => {
abortController.abort();
};
});
if (platform === "win32" || platform === "linux") {
return events;
} else {
// On macOS, we can't know for sure when the watcher is ready.
// So, we just report it as ready when the first event comes through,
// or after 200ms, whichever comes first.
// See https://github.com/nodejs/node/issues/52601
return timer(200).pipe(
map(() => ({event: "Ready"}) as const),
mergeWith(events),
mergeMap((event, index) => [
...(index === 0 ? [ready] : []),
...(event.event === "Ready" ? [] : [event])
])
);
}
}