-
Notifications
You must be signed in to change notification settings - Fork 0
/
poll.ts
115 lines (98 loc) · 2.49 KB
/
poll.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
import { walk, WalkOptions, delay } from "./deps.ts";
export type EventType = "created" | "modified" | "removed";
export type FileEvent = {
type: EventType;
path: string;
};
export type FileEventBatch = {
[key in EventType]: string[];
};
export type PollOptions = {
root?: string;
batch?: boolean;
interval?: number;
walkOptions?: WalkOptions;
};
const defaultWalkOptions = {
includeDirs: false,
exts: [".js", ".ts", ".tsx"]
};
export async function* poll({
root = Deno.cwd(),
batch = false,
interval = 100,
walkOptions
}: PollOptions = {}): AsyncGenerator<FileEvent | FileEventBatch> {
const finalWalkOptions = { ...defaultWalkOptions, ...walkOptions };
let files = await collectFiles(root, finalWalkOptions);
let eventBatch = new EventBatch();
let latestFiles;
while (true) {
latestFiles = await collectFiles(root, finalWalkOptions);
for (const [filename, info] of latestFiles) {
if (!files.has(filename)) {
if (batch) {
eventBatch.created.push(filename);
} else {
yield { type: "created", path: filename };
}
files.delete(filename);
} else if (files.get(filename)?.modified !== info.modified) {
if (batch) {
eventBatch.modified.push(filename);
} else {
yield { type: "modified", path: filename };
}
files.delete(filename);
}
}
for (const [filename] of files) {
if (!latestFiles.has(filename)) {
if (batch) {
eventBatch.removed.push(filename);
} else {
yield { type: "removed", path: filename };
}
}
}
if (batch && eventBatch.hasFiles()) {
yield eventBatch;
}
files = latestFiles;
eventBatch.clear();
await delay(interval);
}
}
type FileMap = Map<string, Deno.FileInfo>;
async function collectFiles(
root: string,
options: WalkOptions
): Promise<FileMap> {
const walkResults = walk(root, {
includeDirs: false,
exts: [".js", ".ts", ".tsx"],
...options
});
const files: FileMap = new Map();
for await (const { filename, info } of walkResults) {
files.set(filename, info);
}
return files;
}
class EventBatch {
public created: string[] = [];
public modified: string[] = [];
public removed: string[] = [];
hasFiles(): boolean {
return (
!!this.created.length ||
!!this.modified.length ||
!!this.removed.length
);
}
clear() {
this.created = [];
this.modified = [];
this.removed = [];
}
}