UNPKG

4.06 kBJavaScriptView Raw
1var fs = require('fs');
2var readdirp = require('readdirp');
3var is_windows = process.platform === 'win32';
4
5module.exports = function() {
6 var watched_files = {};
7 var watched_directories = {};
8 var check_dir_pause = 1000;
9 var checkInterval = undefined;
10
11 // @api public
12 // Watches the directory passed and its contained files
13 // accepts args as an object.
14
15 // @param root(string): the root directory to watch
16 // @param fileFilter(array): ignore these files
17 // @param directoryFilter(array): ignore these files
18 // @param listener(fn(file)): on file change event this will be called
19 // @param complete(fn): on complete of file watching setup
20 function watchDirectory(args) {
21 readdirp({ root: args.root, fileFilter: args.fileFilter, directoryFilter: args.directoryFilter }, function(err, res) {
22 res.files.forEach(function(file) {
23 watchFile(file, args.listener, args.partial);
24 });
25 typeof args.complete == "function" && args.complete();
26 });
27
28 !args.partial && (checkInterval = setInterval(function() {checkDirectory(args)}, check_dir_pause));
29 }
30
31 // @api public
32 // Watches the files passed
33 // accepts args as an object.
34 // @param files(array): a list of files to watch
35 // @param listener(fn(file)): on file change event this will be called
36 // @param complete(fn): on complete of file watching setup
37 function watchFiles(args) {
38 args.files.forEach(function(file) {
39 var o = {
40 fullPath: fs.realpathSync(file),
41 name: fs.realpathSync(file).split('/').pop()
42 };
43 o.fullParentDir = o.fullPath.split('/').slice(0, o.fullPath.split('/').length - 1).join('/')
44
45 watchFile(o, args.listener);
46 });
47
48 typeof args.complete == "function" && args.complete();
49 }
50
51 function unwatchAll() {
52 if (is_windows) {
53 Object.keys(watched_files).forEach(function(key) {
54 watched_files[key].close();
55 });
56 } else {
57 Object.keys(watched_files).forEach(function(key) {
58 fs.unwatchFile(key);
59 });
60 }
61
62 clearInterval(checkInterval);
63 watched_files = {};
64 watched_directories = {};
65 }
66
67 // Checks to see if something in the directory has changed
68 function checkDirectory(args) {
69 Object.keys(watched_directories).forEach(function(path) {
70 var lastModified = watched_directories[path];
71 fs.stat(path, function(err, stats) {
72 var stats_stamp = (new Date(stats.mtime)).getTime();
73 if (stats_stamp != lastModified) {
74 watched_directories[path] = stats_stamp;
75 watchDirectory({
76 root: path,
77 listener: args.listener,
78 fileFilter: args.fileFilter,
79 directoryFilter: args.directoryFilter,
80 partial: true
81 });
82 }
83 });
84 });
85 }
86
87 // Watches the file passed and its containing directory
88 // on change calls given listener with file object
89 function watchFile(file, cb, partial) {
90 storeDirectory(file);
91 if (!watched_files[file.fullPath]) {
92 if (is_windows) {
93 (function() {
94 watched_files[file.fullPath] = fs.watch(file.fullPath, function() {
95 typeof cb === "function" && cb(file);
96 });
97 partial && cb(file);
98 })(file, cb);
99 } else {
100 (function(file, cb) {
101 watched_files[file.fullPath] = true;
102 fs.watchFile(file.fullPath, {interval: 150}, function() {
103 typeof cb === "function" && cb(file);
104 });
105 partial && cb(file);
106 })(file, cb);
107 }
108 }
109 }
110
111 // Sets up a store of the folders being watched
112 // and saves the last modification timestamp for it
113 function storeDirectory(file) {
114 var directory = file.fullParentDir;
115 if (!watched_directories[directory]) {
116 fs.stat(directory, function(err, stats) {
117 watched_directories[directory] = (new Date(stats.mtime)).getTime();
118 });
119 }
120 }
121
122 return {
123 watchDirectory: watchDirectory,
124 watchFiles: watchFiles,
125 unwatchAll: unwatchAll
126 };
127}