/
NodeWatchFileSystem.js
152 lines (142 loc) · 4.29 KB
/
NodeWatchFileSystem.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
148
149
150
151
152
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const Watchpack = require("watchpack");
/** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
/** @typedef {import("../util/fs").WatchFileSystem} WatchFileSystem */
/** @typedef {import("../util/fs").WatchMethod} WatchMethod */
/** @typedef {import("../util/fs").Watcher} Watcher */
class NodeWatchFileSystem {
constructor(inputFileSystem) {
this.inputFileSystem = inputFileSystem;
this.watcherOptions = {
aggregateTimeout: 0
};
this.watcher = new Watchpack(this.watcherOptions);
}
/**
* @param {Iterable<string>} files watched files
* @param {Iterable<string>} directories watched directories
* @param {Iterable<string>} missing watched exitance entries
* @param {number} startTime timestamp of start time
* @param {WatchOptions} options options object
* @param {function(Error=, Map<string, FileSystemInfoEntry>, Map<string, FileSystemInfoEntry>, Set<string>, Set<string>): void} callback aggregated callback
* @param {function(string, number): void} callbackUndelayed callback when the first change was detected
* @returns {Watcher} a watcher
*/
watch(
files,
directories,
missing,
startTime,
options,
callback,
callbackUndelayed
) {
if (!files || typeof files[Symbol.iterator] !== "function") {
throw new Error("Invalid arguments: 'files'");
}
if (!directories || typeof directories[Symbol.iterator] !== "function") {
throw new Error("Invalid arguments: 'directories'");
}
if (!missing || typeof missing[Symbol.iterator] !== "function") {
throw new Error("Invalid arguments: 'missing'");
}
if (typeof callback !== "function") {
throw new Error("Invalid arguments: 'callback'");
}
if (typeof startTime !== "number" && startTime) {
throw new Error("Invalid arguments: 'startTime'");
}
if (typeof options !== "object") {
throw new Error("Invalid arguments: 'options'");
}
if (typeof callbackUndelayed !== "function" && callbackUndelayed) {
throw new Error("Invalid arguments: 'callbackUndelayed'");
}
const oldWatcher = this.watcher;
this.watcher = new Watchpack(options);
if (callbackUndelayed) {
this.watcher.once("change", callbackUndelayed);
}
let fileMap, directoryMap;
this.watcher.once("aggregated", (changes, removals) => {
if (this.inputFileSystem && this.inputFileSystem.purge) {
const fs = this.inputFileSystem;
for (const item of changes) {
fs.purge(item);
}
for (const item of removals) {
fs.purge(item);
}
}
fileMap = new Map();
directoryMap = new Map();
this.watcher.collectTimeInfoEntries(fileMap, directoryMap);
callback(null, fileMap, directoryMap, changes, removals);
});
this.watcher.watch({ files, directories, missing, startTime });
if (oldWatcher) {
oldWatcher.close();
}
return {
close: () => {
if (this.watcher) {
this.watcher.close();
this.watcher = null;
}
},
pause: () => {
if (this.watcher) {
this.watcher.pause();
}
},
getAggregatedRemovals: () => {
const items = this.watcher && this.watcher.aggregatedRemovals;
if (items && this.inputFileSystem && this.inputFileSystem.purge) {
const fs = this.inputFileSystem;
for (const item of items) {
fs.purge(item);
}
}
return items;
},
getAggregatedChanges: () => {
const items = this.watcher && this.watcher.aggregatedChanges;
if (items && this.inputFileSystem && this.inputFileSystem.purge) {
const fs = this.inputFileSystem;
for (const item of items) {
fs.purge(item);
}
}
return items;
},
getFileTimeInfoEntries: () => {
if (fileMap) return fileMap;
if (this.watcher) {
this.watcher.collectTimeInfoEntries(
(fileMap = new Map()),
(directoryMap = new Map())
);
return fileMap;
}
return new Map();
},
getContextTimeInfoEntries: () => {
if (directoryMap) return directoryMap;
if (this.watcher) {
this.watcher.collectTimeInfoEntries(
(fileMap = new Map()),
(directoryMap = new Map())
);
return directoryMap;
}
return new Map();
}
};
}
}
module.exports = NodeWatchFileSystem;