Skip to content

Commit 89d5f48

Browse files
authored
Merge pull request #205 from markjm/markjm/split
Support splitting of files and directories in getTimeInfoEntries
2 parents f1f3586 + 8d14e94 commit 89d5f48

5 files changed

Lines changed: 88 additions & 74 deletions

File tree

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,19 @@ const { changes, removals } = wp.getAggregated();
114114
// when futher changes happen
115115
// Can also be used when paused.
116116

117-
// Watchpack.prototype.getTimeInfoEntries()
118-
var fileTimes = wp.getTimeInfoEntries();
119-
// returns a Map with all known time info objects for files and directories
117+
// Watchpack.prototype.collectTimeInfoEntries(fileInfoEntries: Map<string, Entry>, directoryInfoEntries: Map<string, Entry>)
118+
wp.collectTimeInfoEntries(fileInfoEntries, directoryInfoEntries);
119+
// collects time info objects for all known files and directories
120120
// this include info from files not directly watched
121121
// key: absolute path, value: object with { safeTime, timestamp }
122122
// safeTime: a point in time at which it is safe to say all changes happened before that
123123
// timestamp: only for files, the mtime timestamp of the file
124124

125+
// Watchpack.prototype.getTimeInfoEntries()
126+
var fileTimes = wp.getTimeInfoEntries();
127+
// returns a Map with all known time info objects for files and directories
128+
// similar to collectTimeInfoEntries but returns a single map with all entries
129+
125130
// (deprecated)
126131
// Watchpack.prototype.getTimes()
127132
var fileTimes = wp.getTimes();

lib/DirectoryWatcher.js

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class Watcher extends EventEmitter {
3939
this.directoryWatcher = directoryWatcher;
4040
this.path = filePath;
4141
this.startTime = startTime && +startTime;
42-
this._cachedTimeInfoEntries = undefined;
4342
}
4443

4544
checkStartTime(mtime, initial) {
@@ -130,8 +129,6 @@ class DirectoryWatcher extends EventEmitter {
130129
}
131130

132131
setMissing(itemPath, initial, type) {
133-
this._cachedTimeInfoEntries = undefined;
134-
135132
if (this.initialScan) {
136133
this.initialScanRemoved.add(itemPath);
137134
}
@@ -200,7 +197,6 @@ class DirectoryWatcher extends EventEmitter {
200197
accuracy,
201198
timestamp: mtime
202199
});
203-
this._cachedTimeInfoEntries = undefined;
204200

205201
if (!old) {
206202
const key = withoutCase(filePath);
@@ -243,7 +239,6 @@ class DirectoryWatcher extends EventEmitter {
243239
if (!old) {
244240
const now = Date.now();
245241

246-
this._cachedTimeInfoEntries = undefined;
247242
if (this.nestedWatching) {
248243
this.createNestedWatcher(directoryPath);
249244
} else {
@@ -274,7 +269,6 @@ class DirectoryWatcher extends EventEmitter {
274269
createNestedWatcher(directoryPath) {
275270
const watcher = this.watcherManager.watchDirectory(directoryPath, 1);
276271
watcher.on("change", (filePath, mtime, type, initial) => {
277-
this._cachedTimeInfoEntries = undefined;
278272
this.forEachWatcher(this.path, w => {
279273
if (!initial || w.checkStartTime(mtime, initial)) {
280274
w.emit("change", filePath, mtime, type, initial);
@@ -287,7 +281,6 @@ class DirectoryWatcher extends EventEmitter {
287281
setNestedWatching(flag) {
288282
if (this.nestedWatching !== !!flag) {
289283
this.nestedWatching = !!flag;
290-
this._cachedTimeInfoEntries = undefined;
291284
if (this.nestedWatching) {
292285
for (const directory of this.directories.keys()) {
293286
this.createNestedWatcher(directory);
@@ -425,7 +418,6 @@ class DirectoryWatcher extends EventEmitter {
425418
}
426419
}
427420
this.lastWatchEvent = Date.now();
428-
this._cachedTimeInfoEntries = undefined;
429421
if (!stats) {
430422
this.setMissing(filePath, false, eventType);
431423
} else if (stats.isDirectory()) {
@@ -709,48 +701,47 @@ class DirectoryWatcher extends EventEmitter {
709701
return obj;
710702
}
711703

712-
getTimeInfoEntries() {
713-
if (this._cachedTimeInfoEntries !== undefined)
714-
return this._cachedTimeInfoEntries;
715-
const map = new Map();
704+
collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
716705
let safeTime = this.lastWatchEvent;
717706
for (const [file, entry] of this.files) {
718707
fixupEntryAccuracy(entry);
719708
safeTime = Math.max(safeTime, entry.safeTime);
720-
map.set(file, entry);
709+
fileTimestamps.set(file, entry);
721710
}
722711
if (this.nestedWatching) {
723712
for (const w of this.directories.values()) {
724-
const timeInfoEntries = w.directoryWatcher.getTimeInfoEntries();
725-
for (const [file, entry] of timeInfoEntries) {
726-
if (entry) {
727-
safeTime = Math.max(safeTime, entry.safeTime);
728-
}
729-
map.set(file, entry);
730-
}
713+
safeTime = Math.max(
714+
safeTime,
715+
w.directoryWatcher.collectTimeInfoEntries(
716+
fileTimestamps,
717+
directoryTimestamps,
718+
safeTime
719+
)
720+
);
731721
}
732-
map.set(this.path, {
722+
fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
723+
directoryTimestamps.set(this.path, {
733724
safeTime
734725
});
735726
} else {
736727
for (const dir of this.directories.keys()) {
737728
// No additional info about this directory
738-
map.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
729+
directoryTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
739730
}
740-
map.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
731+
fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
732+
directoryTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
741733
}
742734
if (!this.initialScan) {
743735
for (const watchers of this.watchers.values()) {
744736
for (const watcher of watchers) {
745737
const path = watcher.path;
746-
if (!map.has(path)) {
747-
map.set(path, null);
738+
if (!directoryTimestamps.has(path)) {
739+
directoryTimestamps.set(path, null);
748740
}
749741
}
750742
}
751-
this._cachedTimeInfoEntries = map;
752743
}
753-
return map;
744+
return safeTime;
754745
}
755746

756747
close() {

lib/watchpack.js

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,14 @@ const EventEmitter = require("events").EventEmitter;
1010
const globToRegExp = require("glob-to-regexp");
1111
const watchEventSource = require("./watchEventSource");
1212

13-
let EXISTANCE_ONLY_TIME_ENTRY; // lazy required
14-
1513
const EMPTY_ARRAY = [];
1614
const EMPTY_OPTIONS = {};
1715

18-
function addWatchpackWatchersToSet(watchers, set) {
16+
function addWatchersToSet(watchers, set) {
1917
for (const ww of watchers) {
2018
const w = ww.watcher;
2119
if (!set.has(w.directoryWatcher)) {
2220
set.add(w.directoryWatcher);
23-
addWatchersToSet(w.directoryWatcher.directories.values(), set);
24-
}
25-
}
26-
}
27-
28-
function addWatchersToSet(watchers, set) {
29-
for (const w of watchers) {
30-
if (w !== true && !set.has(w.directoryWatcher)) {
31-
set.add(w.directoryWatcher);
32-
addWatchersToSet(w.directoryWatcher.directories.values(), set);
3321
}
3422
}
3523
}
@@ -324,11 +312,8 @@ class Watchpack extends EventEmitter {
324312

325313
getTimes() {
326314
const directoryWatchers = new Set();
327-
addWatchpackWatchersToSet(this.fileWatchers.values(), directoryWatchers);
328-
addWatchpackWatchersToSet(
329-
this.directoryWatchers.values(),
330-
directoryWatchers
331-
);
315+
addWatchersToSet(this.fileWatchers.values(), directoryWatchers);
316+
addWatchersToSet(this.directoryWatchers.values(), directoryWatchers);
332317
const obj = Object.create(null);
333318
for (const w of directoryWatchers) {
334319
const times = w.getTimes();
@@ -338,35 +323,21 @@ class Watchpack extends EventEmitter {
338323
}
339324

340325
getTimeInfoEntries() {
341-
if (EXISTANCE_ONLY_TIME_ENTRY === undefined) {
342-
EXISTANCE_ONLY_TIME_ENTRY = require("./DirectoryWatcher")
343-
.EXISTANCE_ONLY_TIME_ENTRY;
344-
}
345-
const directoryWatchers = new Set();
346-
addWatchpackWatchersToSet(this.fileWatchers.values(), directoryWatchers);
347-
addWatchpackWatchersToSet(
348-
this.directoryWatchers.values(),
349-
directoryWatchers
350-
);
351326
const map = new Map();
352-
for (const w of directoryWatchers) {
353-
const times = w.getTimeInfoEntries();
354-
for (const [path, entry] of times) {
355-
if (map.has(path)) {
356-
if (entry === EXISTANCE_ONLY_TIME_ENTRY) continue;
357-
const value = map.get(path);
358-
if (value === entry) continue;
359-
if (value !== EXISTANCE_ONLY_TIME_ENTRY) {
360-
map.set(path, Object.assign({}, value, entry));
361-
continue;
362-
}
363-
}
364-
map.set(path, entry);
365-
}
366-
}
327+
this.collectTimeInfoEntries(map, map);
367328
return map;
368329
}
369330

331+
collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
332+
const allWatchers = new Set();
333+
addWatchersToSet(this.fileWatchers.values(), allWatchers);
334+
addWatchersToSet(this.directoryWatchers.values(), allWatchers);
335+
const safeTime = { value: 0 };
336+
for (const w of allWatchers) {
337+
w.collectTimeInfoEntries(fileTimestamps, directoryTimestamps, safeTime);
338+
}
339+
}
340+
370341
getAggregated() {
371342
if (this.aggregateTimer) {
372343
clearTimeout(this.aggregateTimer);

test/Watchpack.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ describe("Watchpack", function() {
121121
it("should not watch a single ignored file (function)", function(done) {
122122
var w = new Watchpack({
123123
aggregateTimeout: 300,
124-
ignored: (entry) => entry.includes("a")
124+
ignored: entry => entry.includes("a")
125125
});
126126
var changeEvents = 0;
127127
var aggregatedEvents = 0;
@@ -550,6 +550,53 @@ describe("Watchpack", function() {
550550
});
551551
});
552552

553+
it("should watch file in a sub directory (passed in maps)", function(done) {
554+
var w = new Watchpack({
555+
aggregateTimeout: 1000
556+
});
557+
var changeEvents = [];
558+
w.on("change", function(file) {
559+
if (changeEvents[changeEvents.length - 1] === file) return;
560+
changeEvents.push(file);
561+
});
562+
w.on("aggregated", function(changes) {
563+
Array.from(changes).should.be.eql([path.join(fixtures, "dir")]);
564+
changeEvents.should.be.eql([path.join(fixtures, "dir", "sub", "a")]);
565+
const files = new Map();
566+
const directories = new Map();
567+
w.collectTimeInfoEntries(files, directories);
568+
const dir = directories.get(path.join(fixtures, "dir"));
569+
const dirAsFile = files.get(path.join(fixtures, "dir"));
570+
const sub = directories.get(path.join(fixtures, "dir", "sub"));
571+
const subAsFile = files.get(path.join(fixtures, "dir", "sub"));
572+
const a = files.get(path.join(fixtures, "dir", "sub", "a"));
573+
dir.should.be.type("object");
574+
dir.should.have.property("safeTime");
575+
dirAsFile.should.be.type("object");
576+
dirAsFile.should.not.have.property("safeTime");
577+
sub.should.be.type("object");
578+
sub.should.have.property("safeTime");
579+
subAsFile.should.be.type("object");
580+
subAsFile.should.not.have.property("safeTime");
581+
a.should.be.type("object");
582+
a.should.have.property("safeTime");
583+
a.should.have.property("timestamp");
584+
sub.safeTime.should.be.aboveOrEqual(a.safeTime);
585+
dir.safeTime.should.be.aboveOrEqual(sub.safeTime);
586+
w.close();
587+
done();
588+
});
589+
testHelper.dir("dir");
590+
testHelper.dir(path.join("dir", "sub"));
591+
testHelper.dir(path.join("dir", "sub2"));
592+
testHelper.tick(function() {
593+
w.watch([], [path.join(fixtures, "dir")]);
594+
testHelper.tick(function() {
595+
testHelper.file(path.join("dir", "sub", "a"));
596+
});
597+
});
598+
});
599+
553600
it("should watch 2 files in a not-existing directory", function(done) {
554601
var w = new Watchpack({
555602
aggregateTimeout: 1000

0 commit comments

Comments
 (0)