This repository was archived by the owner on May 17, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.js
More file actions
168 lines (163 loc) · 4.62 KB
/
Copy pathindex.js
File metadata and controls
168 lines (163 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
const helper = require('think-helper');
const assert = require('assert');
const fs = require('fs');
const debug = require('debug')('think-watcher');
const path = require('path');
/**
* default options
* @type {Object}
*/
const defaultOptions = {
allowExts: ['js', 'es', 'ts'],
filter: (fileInfo, options) => {
const seps = fileInfo.file.split(path.sep);
// filter hidden file
const flag = seps.some(item => {
return item[0] === '.';
});
if (flag) {
return false;
}
const ext = path.extname(fileInfo.file).slice(1);
return options.allowExts.indexOf(ext) !== -1;
}
};
/**
* watcher class
*/
class Watcher {
/**
* constructor
* @param {Object} options watch options
* @param {Function} cb callback when files changed
*/
constructor(options, cb) {
assert(helper.isFunction(cb), 'callback must be a function');
options = this.buildOptions(options);
debug(`srcPath: ${options.srcPath}`);
debug(`diffPath: ${options.diffPath}`);
this.options = options;
this.cb = cb;
this.lastMtime = {};
}
/**
* build Options
* @param {Object} options
*/
buildOptions(options = {}) {
if (helper.isString(options)) {
options = {srcPath: options};
}
let srcPath = options.srcPath;
assert(srcPath, 'srcPath can not be blank');
if (!helper.isArray(srcPath)) {
srcPath = [srcPath];
}
let diffPath = options.diffPath || [];
if (!helper.isArray(diffPath)) {
diffPath = [diffPath];
}
options.srcPath = srcPath;
options.diffPath = diffPath;
if (!options.filter) {
options.filter = defaultOptions.filter;
}
if (!options.allowExts) {
options.allowExts = defaultOptions.allowExts;
}
return options;
}
/**
* get changed files
*/
getChangedFiles() {
const changedFiles = [];
const options = this.options;
options.srcPath.forEach((srcPath, index) => {
assert(path.isAbsolute(srcPath), 'srcPath must be an absolute path');
const diffPath = options.diffPath[index];
const srcFiles = helper.getdirFiles(srcPath).filter(file => {
return options.filter({path: srcPath, file}, options);
});
let diffFiles = [];
if (diffPath) {
diffFiles = helper.getdirFiles(diffPath).filter(file => {
return options.filter({path: diffPath, file}, options);
});
if (srcPath !== diffPath) {
this.removeDeletedFiles(srcFiles, diffFiles, diffPath);
}
}
srcFiles.forEach(file => {
const mtime = fs.statSync(path.join(srcPath, file)).mtime.getTime();
if (diffPath && diffPath !== srcPath) {
let diffFile = '';
diffFiles.some(dfile => {
if (this.removeFileExtName(dfile) === this.removeFileExtName(file)) {
diffFile = dfile;
return true;
}
});
const diffFilePath = path.join(diffPath, diffFile);
// compiled file exist
if (diffFile && helper.isFile(diffFilePath)) {
const diffmtime = fs.statSync(diffFilePath).mtime.getTime();
// if compiled file mtime is after than source file, return
if (diffmtime > mtime) {
return;
}
}
}
if (!this.lastMtime[file] || mtime > this.lastMtime[file]) {
this.lastMtime[file] = mtime;
changedFiles.push({path: srcPath, file});
}
});
});
return changedFiles;
}
/**
* remove files in diffPath when is deleted in srcPath
* @param {Array} srcFiles
* @param {Array} diffFiles
* @param {String} diffPath
*/
removeDeletedFiles(srcFiles, diffFiles, diffPath) {
const srcFilesWithoutExt = srcFiles.map(file => {
return this.removeFileExtName(file);
});
diffFiles.forEach(file => {
const fileWithoutExt = this.removeFileExtName(file);
if (srcFilesWithoutExt.indexOf(fileWithoutExt) === -1) {
const filepath = path.join(diffPath, file);
if (helper.isFile(filepath)) {
fs.unlinkSync(filepath);
}
}
});
}
/**
* remove file extname
* @param {String} file
*/
removeFileExtName(file) {
return file.replace(/\.\w+$/, '');
}
/**
* watch files change
*/
watch() {
const detectFiles = () => {
const changedFiles = this.getChangedFiles();
if (changedFiles.length) {
changedFiles.forEach(item => {
debug(`file changed: path=${item.path}, file=${item.file}`);
this.cb(item);
});
}
setTimeout(detectFiles, this.options.interval || 100);
};
detectFiles();
}
}
module.exports = Watcher;