-
Notifications
You must be signed in to change notification settings - Fork 0
/
fs-watch.js
147 lines (81 loc) · 3.15 KB
/
fs-watch.js
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
connects the fake-chokidar-sender Messages to fs.watch().
Note that we receive chokidar-style events and need to translate them to
fs.watch() events.
Events comparison:
UDP message payload (event, path) fs.watch() event
------------------------------------------ -------------------------------------------
CREATE NEW FILE:
add /full/path/to/file.txt change file.txt
MODIFY FILE:
change /full/path/to/file.txt change file.txt
RENAME (please note the order of events):
add /full/path/to/file-renamed.txt rename file.txt
unlink /full/path/to/file.txt rename file-renamed.txt
DELETE:
unlink /full/path/to/file.txt rename file.txt
CREATE NEW DIRECTORY:
addDir /full/path/to/dir rename dir (not "rename" !!)
RENAME DIRECTORY:
unlinkDir /full/path/to/dir rename dir
addDir /full/path/to/dir-renamed rename dir-renamed
DELETE DIRECTORY:
unlinkDir /full/path/to/dir rename dir
INCOMPATIBILITY WARNING: Please note that *renaming* a file will result in
incorrect "change file-renamed.txt", "rename file.txt" events (wrong event
and wrong order). This probably is not relevant for Webpack/Watchpack.
*/
const fs = require("fs");
const server = require("./server.js");
const origWatch = fs.watch;
exports.injectFsWatch = function(options) {
const { debug } = options || {};
const watchers = [];
if (fs.watch !== origWatch)
throw new Error('fs.watch() has already been monkeypatched');
server.initServer(options, message => {
const { event, path } = JSON.parse(message);
const [ dir, fn ] = splitDirFn(path);
if (debug)
console.log("+++", event, path, `(${watchers.length})`);
for (const { watchFn, handle } of watchers) {
if (watchFn === dir) {
const fswEvent = ['add', 'change'].includes(event) ? 'change' : 'rename';
//console.log(" ... match", watchFn, "-->", fswEvent, fn)
handle.emit('change', fswEvent, fn);
}
}
});
fs.watch = function(watchFn, options=undefined, listener=undefined) {
if (options) {
throw new Error('fs.watch() called with "options" arg. This is currently' +
' not supported by fake-chokidar.');
}
if (listener) {
throw new Error('fs.watch() called with "listener" arg. This is currently' +
' not supported by fake-chokidar.');
}
// NB: Webpack 2+ (Watchpack) normally will always be a directory name
// (not a regular file).
// We call the original fs.watch() just to get a full featured return
// value. We don't expect this FSWatcher to invoke any events (even if
// it does, it's fine). Instead, we will inject our own events.
const handle = origWatch(watchFn);
const watchersRef = {
watchFn,
handle: handle,
};
watchers.push(watchersRef);
handle.on('close', () => {
const idx = watchers.indexOf(watchersRef);
if (idx >= 0)
watchers.splice(idx, 1);
});
return handle;
}
}
function splitDirFn(fn) {
const parts = fn.split("/");
const name = parts.pop();
return [ parts.join("/"), name ];
}