UNPKG

6.55 kBJavaScriptView Raw
1'use strict';
2
3function _events() {
4 const data = require('events');
5
6 _events = function () {
7 return data;
8 };
9
10 return data;
11}
12
13function path() {
14 const data = _interopRequireWildcard(require('path'));
15
16 path = function () {
17 return data;
18 };
19
20 return data;
21}
22
23function _anymatch() {
24 const data = _interopRequireDefault(require('anymatch'));
25
26 _anymatch = function () {
27 return data;
28 };
29
30 return data;
31}
32
33function fs() {
34 const data = _interopRequireWildcard(require('graceful-fs'));
35
36 fs = function () {
37 return data;
38 };
39
40 return data;
41}
42
43function _micromatch() {
44 const data = _interopRequireDefault(require('micromatch'));
45
46 _micromatch = function () {
47 return data;
48 };
49
50 return data;
51}
52
53function _walker() {
54 const data = _interopRequireDefault(require('walker'));
55
56 _walker = function () {
57 return data;
58 };
59
60 return data;
61}
62
63function _interopRequireDefault(obj) {
64 return obj && obj.__esModule ? obj : {default: obj};
65}
66
67function _getRequireWildcardCache(nodeInterop) {
68 if (typeof WeakMap !== 'function') return null;
69 var cacheBabelInterop = new WeakMap();
70 var cacheNodeInterop = new WeakMap();
71 return (_getRequireWildcardCache = function (nodeInterop) {
72 return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
73 })(nodeInterop);
74}
75
76function _interopRequireWildcard(obj, nodeInterop) {
77 if (!nodeInterop && obj && obj.__esModule) {
78 return obj;
79 }
80 if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
81 return {default: obj};
82 }
83 var cache = _getRequireWildcardCache(nodeInterop);
84 if (cache && cache.has(obj)) {
85 return cache.get(obj);
86 }
87 var newObj = {};
88 var hasPropertyDescriptor =
89 Object.defineProperty && Object.getOwnPropertyDescriptor;
90 for (var key in obj) {
91 if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
92 var desc = hasPropertyDescriptor
93 ? Object.getOwnPropertyDescriptor(obj, key)
94 : null;
95 if (desc && (desc.get || desc.set)) {
96 Object.defineProperty(newObj, key, desc);
97 } else {
98 newObj[key] = obj[key];
99 }
100 }
101 }
102 newObj.default = obj;
103 if (cache) {
104 cache.set(obj, newObj);
105 }
106 return newObj;
107}
108
109function _defineProperty(obj, key, value) {
110 if (key in obj) {
111 Object.defineProperty(obj, key, {
112 value: value,
113 enumerable: true,
114 configurable: true,
115 writable: true
116 });
117 } else {
118 obj[key] = value;
119 }
120 return obj;
121}
122
123// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
124// @ts-ignore: this is for CI which runs linux and might not have this
125let fsevents = null;
126
127try {
128 fsevents = require('fsevents');
129} catch {
130 // Optional dependency, only supported on Darwin.
131}
132
133const CHANGE_EVENT = 'change';
134const DELETE_EVENT = 'delete';
135const ADD_EVENT = 'add';
136const ALL_EVENT = 'all';
137
138/**
139 * Export `FSEventsWatcher` class.
140 * Watches `dir`.
141 */
142class FSEventsWatcher extends _events().EventEmitter {
143 static isSupported() {
144 return fsevents !== null;
145 }
146
147 static normalizeProxy(callback) {
148 return (filepath, stats) => callback(path().normalize(filepath), stats);
149 }
150
151 static recReaddir(
152 dir,
153 dirCallback,
154 fileCallback,
155 endCallback,
156 errorCallback,
157 ignored
158 ) {
159 (0, _walker().default)(dir)
160 .filterDir(
161 currentDir => !ignored || !(0, _anymatch().default)(ignored, currentDir)
162 )
163 .on('dir', FSEventsWatcher.normalizeProxy(dirCallback))
164 .on('file', FSEventsWatcher.normalizeProxy(fileCallback))
165 .on('error', errorCallback)
166 .on('end', () => {
167 endCallback();
168 });
169 }
170
171 constructor(dir, opts) {
172 if (!fsevents) {
173 throw new Error(
174 '`fsevents` unavailable (this watcher can only be used on Darwin)'
175 );
176 }
177
178 super();
179
180 _defineProperty(this, 'root', void 0);
181
182 _defineProperty(this, 'ignored', void 0);
183
184 _defineProperty(this, 'glob', void 0);
185
186 _defineProperty(this, 'dot', void 0);
187
188 _defineProperty(this, 'hasIgnore', void 0);
189
190 _defineProperty(this, 'doIgnore', void 0);
191
192 _defineProperty(this, 'fsEventsWatchStopper', void 0);
193
194 _defineProperty(this, '_tracked', void 0);
195
196 this.dot = opts.dot || false;
197 this.ignored = opts.ignored;
198 this.glob = Array.isArray(opts.glob) ? opts.glob : [opts.glob];
199 this.hasIgnore =
200 Boolean(opts.ignored) && !(Array.isArray(opts) && opts.length > 0);
201 this.doIgnore = opts.ignored
202 ? (0, _anymatch().default)(opts.ignored)
203 : () => false;
204 this.root = path().resolve(dir);
205 this.fsEventsWatchStopper = fsevents.watch(
206 this.root,
207 this.handleEvent.bind(this)
208 );
209 this._tracked = new Set();
210 FSEventsWatcher.recReaddir(
211 this.root,
212 filepath => {
213 this._tracked.add(filepath);
214 },
215 filepath => {
216 this._tracked.add(filepath);
217 },
218 this.emit.bind(this, 'ready'),
219 this.emit.bind(this, 'error'),
220 this.ignored
221 );
222 }
223 /**
224 * End watching.
225 */
226
227 async close(callback) {
228 await this.fsEventsWatchStopper();
229 this.removeAllListeners();
230
231 if (typeof callback === 'function') {
232 process.nextTick(callback.bind(null, null, true));
233 }
234 }
235
236 isFileIncluded(relativePath) {
237 if (this.doIgnore(relativePath)) {
238 return false;
239 }
240
241 return this.glob.length
242 ? (0, _micromatch().default)([relativePath], this.glob, {
243 dot: this.dot
244 }).length > 0
245 : this.dot ||
246 (0, _micromatch().default)([relativePath], '**/*').length > 0;
247 }
248
249 handleEvent(filepath) {
250 const relativePath = path().relative(this.root, filepath);
251
252 if (!this.isFileIncluded(relativePath)) {
253 return;
254 }
255
256 fs().lstat(filepath, (error, stat) => {
257 if (error && error.code !== 'ENOENT') {
258 this.emit('error', error);
259 return;
260 }
261
262 if (error) {
263 // Ignore files that aren't tracked and don't exist.
264 if (!this._tracked.has(filepath)) {
265 return;
266 }
267
268 this._emit(DELETE_EVENT, relativePath);
269
270 this._tracked.delete(filepath);
271
272 return;
273 }
274
275 if (this._tracked.has(filepath)) {
276 this._emit(CHANGE_EVENT, relativePath, stat);
277 } else {
278 this._tracked.add(filepath);
279
280 this._emit(ADD_EVENT, relativePath, stat);
281 }
282 });
283 }
284 /**
285 * Emit events.
286 */
287
288 _emit(type, file, stat) {
289 this.emit(type, file, this.root, stat);
290 this.emit(ALL_EVENT, type, file, this.root, stat);
291 }
292}
293
294module.exports = FSEventsWatcher;