UNPKG

2.36 kBJavaScriptView Raw
1'use strict'
2
3const mm = require('minimatch')
4const braces = require('braces')
5const PatternUtils = require('./utils/pattern-utils')
6
7const helper = require('./helper')
8const log = require('./logger').create('watcher')
9
10const DIR_SEP = require('path').sep
11
12function watchPatterns (patterns, watcher) {
13 let expandedPatterns = []
14 patterns.map((pattern) => {
15 // expand ['a/{b,c}'] to ['a/b', 'a/c']
16 expandedPatterns = expandedPatterns.concat(braces.expand(pattern, { keepEscaping: true }))
17 })
18 expandedPatterns
19 .map(PatternUtils.getBaseDir)
20 .filter((path, index, paths) => paths.indexOf(path) === index) // filter unique values
21 .forEach((path, index, paths) => {
22 if (!paths.some((p) => path.startsWith(p + DIR_SEP))) {
23 watcher.add(path)
24 log.debug(`Watching "${path}"`)
25 }
26 })
27}
28
29function checkAnyPathMatch (patterns, path) {
30 return patterns.some((pattern) => mm(path, pattern, { dot: true }))
31}
32
33function createIgnore (patterns, excludes) {
34 return function (path, stat) {
35 if (stat && !stat.isDirectory()) {
36 return !checkAnyPathMatch(patterns, path) || checkAnyPathMatch(excludes, path)
37 } else {
38 return false
39 }
40 }
41}
42
43function getWatchedPatterns (patterns) {
44 return patterns
45 .filter((pattern) => pattern.watched)
46 .map((pattern) => pattern.pattern)
47}
48
49function watch (patterns, excludes, fileList, usePolling, emitter) {
50 const watchedPatterns = getWatchedPatterns(patterns)
51 // Lazy-load 'chokidar' to make the dependency optional. This is desired when
52 // third-party watchers are in use.
53 const chokidar = require('chokidar')
54 const watcher = new chokidar.FSWatcher({
55 usePolling: usePolling,
56 ignorePermissionErrors: true,
57 ignoreInitial: true,
58 ignored: createIgnore(watchedPatterns, excludes)
59 })
60
61 watchPatterns(watchedPatterns, watcher)
62
63 watcher
64 .on('add', (path) => fileList.addFile(helper.normalizeWinPath(path)))
65 .on('change', (path) => fileList.changeFile(helper.normalizeWinPath(path)))
66 .on('unlink', (path) => fileList.removeFile(helper.normalizeWinPath(path)))
67 .on('error', log.debug.bind(log))
68
69 emitter.on('exit', (done) => {
70 watcher.close()
71 done()
72 })
73
74 return watcher
75}
76
77watch.$inject = [
78 'config.files',
79 'config.exclude',
80 'fileList',
81 'config.usePolling',
82 'emitter'
83]
84
85module.exports = watch