86 lines
2.3 KiB
JavaScript
86 lines
2.3 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
const mm = require('minimatch')
|
||
|
const braces = require('braces')
|
||
|
const PatternUtils = require('./utils/pattern-utils')
|
||
|
|
||
|
const helper = require('./helper')
|
||
|
const log = require('./logger').create('watcher')
|
||
|
|
||
|
const DIR_SEP = require('path').sep
|
||
|
|
||
|
function watchPatterns (patterns, watcher) {
|
||
|
let expandedPatterns = []
|
||
|
patterns.map((pattern) => {
|
||
|
// expand ['a/{b,c}'] to ['a/b', 'a/c']
|
||
|
expandedPatterns = expandedPatterns.concat(braces.expand(pattern, { keepEscaping: true }))
|
||
|
})
|
||
|
expandedPatterns
|
||
|
.map(PatternUtils.getBaseDir)
|
||
|
.filter((path, index, paths) => paths.indexOf(path) === index) // filter unique values
|
||
|
.forEach((path, index, paths) => {
|
||
|
if (!paths.some((p) => path.startsWith(p + DIR_SEP))) {
|
||
|
watcher.add(path)
|
||
|
log.debug(`Watching "${path}"`)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
function checkAnyPathMatch (patterns, path) {
|
||
|
return patterns.some((pattern) => mm(path, pattern, { dot: true }))
|
||
|
}
|
||
|
|
||
|
function createIgnore (patterns, excludes) {
|
||
|
return function (path, stat) {
|
||
|
if (stat && !stat.isDirectory()) {
|
||
|
return !checkAnyPathMatch(patterns, path) || checkAnyPathMatch(excludes, path)
|
||
|
} else {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getWatchedPatterns (patterns) {
|
||
|
return patterns
|
||
|
.filter((pattern) => pattern.watched)
|
||
|
.map((pattern) => pattern.pattern)
|
||
|
}
|
||
|
|
||
|
function watch (patterns, excludes, fileList, usePolling, emitter) {
|
||
|
const watchedPatterns = getWatchedPatterns(patterns)
|
||
|
// Lazy-load 'chokidar' to make the dependency optional. This is desired when
|
||
|
// third-party watchers are in use.
|
||
|
const chokidar = require('chokidar')
|
||
|
const watcher = new chokidar.FSWatcher({
|
||
|
usePolling: usePolling,
|
||
|
ignorePermissionErrors: true,
|
||
|
ignoreInitial: true,
|
||
|
ignored: createIgnore(watchedPatterns, excludes)
|
||
|
})
|
||
|
|
||
|
watchPatterns(watchedPatterns, watcher)
|
||
|
|
||
|
watcher
|
||
|
.on('add', (path) => fileList.addFile(helper.normalizeWinPath(path)))
|
||
|
.on('change', (path) => fileList.changeFile(helper.normalizeWinPath(path)))
|
||
|
.on('unlink', (path) => fileList.removeFile(helper.normalizeWinPath(path)))
|
||
|
.on('error', log.debug.bind(log))
|
||
|
|
||
|
emitter.on('exit', (done) => {
|
||
|
watcher.close()
|
||
|
done()
|
||
|
})
|
||
|
|
||
|
return watcher
|
||
|
}
|
||
|
|
||
|
watch.$inject = [
|
||
|
'config.files',
|
||
|
'config.exclude',
|
||
|
'fileList',
|
||
|
'config.usePolling',
|
||
|
'emitter'
|
||
|
]
|
||
|
|
||
|
module.exports = watch
|