UNPKG

2.65 kBJavaScriptView Raw
1var _ = require('underscore'),
2 EventEmitter = require('events').EventEmitter,
3 fu = require('./fileUtil'),
4 path = require('path'),
5 watcher = require('./util/watcher');
6
7function WatchManager() {
8 EventEmitter.call(this);
9
10 this.reset();
11
12 this._exec = this.setupExec();
13}
14
15WatchManager.prototype = {
16 configFile: function(path, mixins, callback) {
17 if (_.isFunction(mixins)) {
18 callback = mixins;
19 mixins = undefined;
20 }
21
22 var self = this;
23 watcher.watchFile(path, mixins || [], function() {
24 self.emit('watch-change', {fileName: path, config: true});
25
26 self.pushChange({callback: callback, fileName: path, config: true});
27 });
28 },
29 moduleOutput: function(status, callback) {
30 var self = this;
31
32 function theWatcher(type, filename, sourceChange) {
33 self.emit('watch-change', {fileName: sourceChange, output: status.fileName});
34 self.pushChange({
35 callback: callback,
36 type: type,
37 fileName: status.fileName,
38 sourceChange: sourceChange
39 });
40 }
41
42 var input = status.inputs.map(function(input) { return fu.resolvePath(input.dir || input); }),
43 removed = _.difference(this.watching[status.fileName], input);
44
45 if (removed.length) {
46 watcher.unwatch(status.fileName, removed);
47 }
48
49 watcher.watchFile({ virtual: status.fileName }, input, theWatcher);
50 this.watching[status.fileName] = input;
51 },
52
53
54 setupExec: function() {
55 return _.debounce(_.bind(this.flushQueue, this), 500);
56 },
57 flushQueue: function() {
58 if (this.queue.length) {
59 _.each(this.queue, function(change) {
60 change.callback();
61 });
62 this.queue = [];
63 }
64 },
65
66 reset: function() {
67 // Cleanup what we can, breaking things along the way
68 // WARN: This prevents concurrent execution within the same process.
69 watcher.unwatchAll();
70
71 this.watching = {};
72 this.queue = [];
73 },
74 pushChange: function(change) {
75 fu.resetCache(change.sourceChange);
76 if (change.type === 'remove' && change.sourceChange) {
77 fu.resetCache(path.dirname(change.sourceChange));
78 }
79
80 if (_.find(this.queue, function(existing) {
81 return existing.config || (change.fileName && (existing.fileName === change.fileName));
82 })) {
83 // If we have a pending config change or changes to the same file that has not started then
84 // we can ignore subsequent changes
85 return;
86 }
87
88 if (change.config) {
89 this.reset();
90 }
91
92 this.queue.push(change);
93 this._exec();
94 }
95};
96
97WatchManager.prototype.__proto__ = EventEmitter.prototype;
98
99exports = module.exports = WatchManager;