1 | var chokidar = require('chokidar')
|
2 | var mm = require('minimatch')
|
3 | var expandBraces = require('expand-braces')
|
4 |
|
5 | var helper = require('./helper')
|
6 | var log = require('./logger').create('watcher')
|
7 |
|
8 | var DIR_SEP = require('path').sep
|
9 |
|
10 |
|
11 | var baseDirFromPattern = function (pattern) {
|
12 | return pattern
|
13 | .replace(/[/\\][^/\\]*\*.*$/, '')
|
14 | .replace(/[/\\][^/\\]*[!+]\(.*$/, '')
|
15 | .replace(/[/\\][^/\\]*\)\?.*$/, '') || DIR_SEP
|
16 | }
|
17 |
|
18 | var watchPatterns = function (patterns, watcher) {
|
19 |
|
20 | var pathsToWatch = []
|
21 | var uniqueMap = {}
|
22 | var path
|
23 |
|
24 |
|
25 | patterns = expandBraces(patterns)
|
26 |
|
27 | patterns.forEach(function (pattern) {
|
28 | path = baseDirFromPattern(pattern)
|
29 | if (!uniqueMap[path]) {
|
30 | uniqueMap[path] = true
|
31 | pathsToWatch.push(path)
|
32 | }
|
33 | })
|
34 |
|
35 |
|
36 | pathsToWatch.forEach(function (path) {
|
37 | if (!pathsToWatch.some(function (p) {
|
38 | return p !== path && path.substr(0, p.length + 1) === p + DIR_SEP
|
39 | })) {
|
40 | watcher.add(path)
|
41 | log.debug('Watching "%s"', path)
|
42 | }
|
43 | })
|
44 | }
|
45 |
|
46 |
|
47 | var createIgnore = function (patterns, excludes) {
|
48 | return function (path, stat) {
|
49 | if (!stat || stat.isDirectory()) {
|
50 | return false
|
51 | }
|
52 |
|
53 |
|
54 | if (!patterns.some(function (pattern) {
|
55 | return mm(path, pattern, {dot: true})
|
56 | })) {
|
57 | return true
|
58 | }
|
59 |
|
60 |
|
61 | if (excludes.some(function (pattern) {
|
62 | return mm(path, pattern, {dot: true})
|
63 | })) {
|
64 | return true
|
65 | }
|
66 |
|
67 | return false
|
68 | }
|
69 | }
|
70 |
|
71 | var onlyWatchedTrue = function (pattern) {
|
72 | return pattern.watched
|
73 | }
|
74 |
|
75 | var getWatchedPatterns = function (patternObjects) {
|
76 | return patternObjects.filter(onlyWatchedTrue).map(function (patternObject) {
|
77 | return patternObject.pattern
|
78 | })
|
79 | }
|
80 |
|
81 | exports.watch = function (patterns, excludes, fileList, usePolling, emitter) {
|
82 | var watchedPatterns = getWatchedPatterns(patterns)
|
83 | var options = {
|
84 | usePolling: usePolling,
|
85 | ignorePermissionErrors: true,
|
86 | ignoreInitial: true,
|
87 | ignored: createIgnore(watchedPatterns, excludes)
|
88 | }
|
89 | var chokidarWatcher = new chokidar.FSWatcher(options)
|
90 |
|
91 | watchPatterns(watchedPatterns, chokidarWatcher)
|
92 |
|
93 | var bind = function (fn) {
|
94 | return function (path) {
|
95 | return fn.call(fileList, helper.normalizeWinPath(path))
|
96 | }
|
97 | }
|
98 |
|
99 |
|
100 | chokidarWatcher.on('add', bind(fileList.addFile))
|
101 | .on('change', bind(fileList.changeFile))
|
102 | .on('unlink', bind(fileList.removeFile))
|
103 |
|
104 |
|
105 | .on('error', function (e) {
|
106 | log.debug(e)
|
107 | })
|
108 |
|
109 | emitter.on('exit', function (done) {
|
110 | chokidarWatcher.close()
|
111 | done()
|
112 | })
|
113 |
|
114 | return chokidarWatcher
|
115 | }
|
116 |
|
117 | exports.watch.$inject = ['config.files', 'config.exclude', 'fileList', 'config.usePolling',
|
118 | 'emitter']
|