node-sass-watcher
Version:
SCSS watcher with post-processing.
127 lines (100 loc) • 3.84 kB
JavaScript
var fs = require('fs');
var path = require('path');
var util = require('util');
var grapher = require('sass-graph');
var chokidar = require('chokidar');
var Emitter = require('events').EventEmitter;
var difference = require('lodash.difference');
function Watcher(inputPath, options) {
options = options || {};
this.inputPath = path.resolve(inputPath);
this.includePaths = options.includePaths ? options.includePaths.map(function(includePath) {
return path.resolve(includePath);
}) : [];
this.rootDir = options.rootDir ? path.resolve(options.rootDir) : process.cwd();
this.verbosity = options.verbosity || 0;
this.includeExtensions = options.includeExtensions || Watcher.defaultExtensions;
this.watchedFiles = [];
if (this.verbosity >= 1) {
console.warn('Start watching "%s"...', this.inputPath);
}
process.nextTick(this.emit.bind(this, 'init'));
}
util.inherits(Watcher, Emitter);
Watcher.defaultExtensions = ['scss', 'sass', 'css'];
Watcher.prototype.run = function() {
this.initRootDirWatcher();
this.initInputPathWatcher();
};
Watcher.prototype.initRootDirWatcher = function() {
var self = this;
this.rootDirWatcher = chokidar.watch(this.rootDir, {
// Ignore unsupported file extensions
ignored: new RegExp('(\\.(?!(' + this.includeExtensions.join('|') + '))\\w+$|^\\w+$)')
});
['add', 'addDir', 'unlink', 'unlinkDir'].forEach(function(eventName) {
self.rootDirWatcher.on(eventName, function(path) {
var info = self.updateInputPathWatcher();
if (info[0].length > 0 || info[1].length > 0) {
if (self.verbosity >= 2) {
switch (eventName) {
case 'add':
console.warn('New file "%s" is added', path);
break;
case 'addDir':
console.warn('New directory "%s" is added', path);
break;
case 'unlink':
console.warn('File "%s" is removed', path);
break;
case 'unlinkDir':
console.warn('Directory "%s" is removed', path);
break;
}
}
self.emit('update');
}
});
});
};
Watcher.prototype.initInputPathWatcher = function() {
var self = this;
this.watchedFiles = this.getIncludedFiles();
this.inputPathWatcher = chokidar.watch(this.watchedFiles);
if (self.verbosity >= 2) {
console.warn("Initially watched files: %s", this.watchedFiles.join(', '));
}
this.inputPathWatcher.on('change', function(filePath) {
self.updateInputPathWatcher();
if (self.verbosity >= 2) {
console.warn('File "%s" is modified', filePath);
}
self.emit('update');
});
};
Watcher.prototype.getIncludedFiles = function() {
var newWatchedFilesGraph = grapher.parseFile(this.inputPath, {
loadPaths: this.includePaths,
extensions: this.includeExtensions
});
return Object.keys(newWatchedFilesGraph.index);
};
Watcher.prototype.updateInputPathWatcher = function() {
var newWatchedFiles = this.getIncludedFiles();
var startWatchingFiles = difference(newWatchedFiles, this.watchedFiles);
var stopWatchingFiles = difference(this.watchedFiles, newWatchedFiles);
this.watchedFiles = newWatchedFiles;
if (this.verbosity >= 3 && startWatchingFiles.length) {
console.warn("Start watching files: %s", startWatchingFiles.join(', '));
}
if (this.verbosity >= 3 && stopWatchingFiles.length) {
console.warn("Stop watching files: %s", stopWatchingFiles.join(', '));
}
if (this.verbosity >= 3 && startWatchingFiles.length + stopWatchingFiles.length) {
console.warn("Currently watched files: %s", newWatchedFiles.join(', '));
}
this.inputPathWatcher.add(startWatchingFiles);
this.inputPathWatcher.unwatch(stopWatchingFiles);
return [startWatchingFiles, stopWatchingFiles];
};
module.exports = Watcher;