UNPKG

2.58 kBJavaScriptView Raw
1'use strict';
2
3const fs = require('fs');
4const path = require('path');
5const watch = require('@cnakazawa/watch');
6const common = require('./common');
7const EventEmitter = require('events').EventEmitter;
8
9/**
10 * Constants
11 */
12
13const DEFAULT_DELAY = common.DEFAULT_DELAY;
14const CHANGE_EVENT = common.CHANGE_EVENT;
15const DELETE_EVENT = common.DELETE_EVENT;
16const ADD_EVENT = common.ADD_EVENT;
17const ALL_EVENT = common.ALL_EVENT;
18
19/**
20 * Export `PollWatcher` class.
21 * Watches `dir`.
22 *
23 * @class PollWatcher
24 * @param String dir
25 * @param {Object} opts
26 * @public
27 */
28
29module.exports = class PollWatcher extends EventEmitter {
30 constructor(dir, opts) {
31 super();
32
33 opts = common.assignOptions(this, opts);
34
35 this.watched = Object.create(null);
36 this.root = path.resolve(dir);
37
38 watch.createMonitor(
39 this.root,
40 {
41 interval: (opts.interval || DEFAULT_DELAY) / 1000,
42 filter: this.filter.bind(this),
43 },
44 this.init.bind(this)
45 );
46 }
47
48 /**
49 * Given a fullpath of a file or directory check if we need to watch it.
50 *
51 * @param {string} filepath
52 * @param {object} stat
53 * @private
54 */
55
56 filter(filepath, stat) {
57 return (
58 stat.isDirectory() ||
59 common.isFileIncluded(
60 this.globs,
61 this.dot,
62 this.doIgnore,
63 path.relative(this.root, filepath)
64 )
65 );
66 }
67
68 /**
69 * Initiate the polling file watcher with the event emitter passed from
70 * `watch.watchTree`.
71 *
72 * @param {EventEmitter} monitor
73 * @public
74 */
75
76 init(monitor) {
77 this.watched = monitor.files;
78 monitor.on('changed', this.emitEvent.bind(this, CHANGE_EVENT));
79 monitor.on('removed', this.emitEvent.bind(this, DELETE_EVENT));
80 monitor.on('created', this.emitEvent.bind(this, ADD_EVENT));
81 // 1 second wait because mtime is second-based.
82 setTimeout(this.emit.bind(this, 'ready'), 1000);
83 }
84
85 /**
86 * Transform and emit an event comming from the poller.
87 *
88 * @param {EventEmitter} monitor
89 * @public
90 */
91
92 emitEvent(type, file, stat) {
93 file = path.relative(this.root, file);
94
95 if (type === DELETE_EVENT) {
96 // Matching the non-polling API
97 stat = null;
98 }
99
100 this.emit(type, file, this.root, stat);
101 this.emit(ALL_EVENT, type, file, this.root, stat);
102 }
103
104 /**
105 * End watching.
106 *
107 * @public
108 */
109
110 close(callback) {
111 Object.keys(this.watched).forEach(filepath => fs.unwatchFile(filepath));
112 this.removeAllListeners();
113 if (typeof callback === 'function') {
114 setImmediate(callback.bind(null, null, true));
115 }
116 }
117};