0.6.1
fix: catch and warn if remove watcher is called but no watcher was started.master
parent
3d036ac7a0
commit
f903ef7071
|
@ -1,29 +1,29 @@
|
|||
import Watcher from '../src/watcher.js'
|
||||
import onDeath from 'ondeath'
|
||||
import onDeath from 'ondeath'
|
||||
|
||||
const USE_CUSTOM_HANDLER=true
|
||||
const DEBOUNCE=0
|
||||
const READY_TIMEOUT=null
|
||||
const USE_CUSTOM_HANDLER = true
|
||||
const DEBOUNCE = 0
|
||||
const READY_TIMEOUT = null
|
||||
|
||||
;
|
||||
;
|
||||
(async () => {
|
||||
let options = {
|
||||
source:'./example/repo/**',
|
||||
ignored:['**/dontwatch.js'],
|
||||
ignoreList:['./example/repo/.gitignore'],
|
||||
source: './example/repo/**',
|
||||
ignored: ['**/dontwatch.js'],
|
||||
ignoreList: ['./example/repo/.gitignore'],
|
||||
debounce: DEBOUNCE,
|
||||
readyTimeout:READY_TIMEOUT
|
||||
readyTimeout: READY_TIMEOUT
|
||||
}
|
||||
|
||||
let watcher = new Watcher(options)
|
||||
|
||||
watcher.on('ready', (state,opts) =>{
|
||||
console.log('watched files indexed and ready??',state)
|
||||
watcher.on('ready', (state, opts) => {
|
||||
console.log('watched files indexed and ready??', state)
|
||||
if (opts) console.dir(opts)
|
||||
})
|
||||
|
||||
watcher.on('watching', (state, opts) =>{
|
||||
console.log('watcher is active and listening for changes?',state)
|
||||
watcher.on('watching', (state, opts) => {
|
||||
console.log('watcher is active and listening for changes?', state)
|
||||
if (opts) console.dir(opts)
|
||||
})
|
||||
|
||||
|
@ -31,10 +31,10 @@ const READY_TIMEOUT=null
|
|||
await watcher.start(
|
||||
// {ignored:'**/another'}
|
||||
)
|
||||
|
||||
|
||||
if (USE_CUSTOM_HANDLER) {
|
||||
watcher.registerHandler(
|
||||
function handler (type, f) {
|
||||
function handler(type, f) {
|
||||
this.emit('custom', f, type)
|
||||
} // end handler
|
||||
)
|
||||
|
@ -43,20 +43,20 @@ const READY_TIMEOUT=null
|
|||
console.log(`custom handler ======= file ${file} was ${type} ==========`)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// default handler event is `changed`
|
||||
else watcher.on('changed',
|
||||
(file,type) => {
|
||||
(file, type) => {
|
||||
console.log(`======= file ${file} was ${type} ==========`)
|
||||
})
|
||||
|
||||
|
||||
|
||||
onDeath( () => {
|
||||
onDeath(() => {
|
||||
console.log('\nHe\'s dead Jim')
|
||||
watcher.remove()
|
||||
})
|
||||
|
||||
})().catch(err => {
|
||||
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||
console.error('FATAL: UNABLE TO START SYSTEM!\n', err)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@uci-utils/watcher",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"description": "File System Watcher Class that emits events",
|
||||
"main": "src/watcher.js",
|
||||
"type": "module",
|
||||
|
|
114
src/watcher.js
114
src/watcher.js
|
@ -13,42 +13,42 @@ let log = {}
|
|||
const READY_TIMEOUT = 10000 //default
|
||||
|
||||
class Watcher extends Emitter {
|
||||
constructor(opts={}) {
|
||||
constructor(opts = {}) {
|
||||
super()
|
||||
log = logger({ package:'@uci-utils/watcher', class:'Watcher', file:'src/watcher.js'})
|
||||
log = logger({ package: '@uci-utils/watcher', class: 'Watcher', file: 'src/watcher.js' })
|
||||
opts.unlinkDir = 'unlinkDir' in opts ? opts.unlinkDir : true // delete file even on by default
|
||||
this.opts = opts
|
||||
this.timeout = process.env.READY_TIMEOUT || opts.readyTimeout || READY_TIMEOUT
|
||||
this._ignored = opts.ignored ? (Array.isArray(opts.ignored) ? opts.ignored : opts.ignored.split(',')) : []
|
||||
this.handler = opts.handler || _handler
|
||||
this._ready=false
|
||||
this._watching=false
|
||||
this._ready = false
|
||||
this._watching = false
|
||||
return this
|
||||
}
|
||||
|
||||
get watching () {
|
||||
get watching() {
|
||||
return this._watching
|
||||
}
|
||||
|
||||
get ready () {
|
||||
get ready() {
|
||||
return this._ready
|
||||
}
|
||||
|
||||
registerHandler(func,opts) {
|
||||
opts = Object.assign({},this.opts,opts)
|
||||
if (!this._watcher) return 'failed: watcher not initialized'
|
||||
if (typeof func ==='function') this.handler = func
|
||||
registerHandler(func, opts) {
|
||||
opts = Object.assign({}, this.opts, opts)
|
||||
if (!this._watcher) return 'failed: watcher not initialized'
|
||||
if (typeof func === 'function') this.handler = func
|
||||
else if (func) opts = func
|
||||
opts = Object.assign({},this.opts,opts)
|
||||
opts = Object.assign({}, this.opts, opts)
|
||||
let handler
|
||||
if (opts.debounce)
|
||||
handler = debounce((type, file) => {
|
||||
handler = debounce((type, file) => {
|
||||
log.debug(`waited : ${opts.debounce}ms before calling handler`)
|
||||
log.info('debounced handler, only last event is emitted')
|
||||
this.handler.call(this,type,file)
|
||||
},{wait:opts.debounce})
|
||||
this.handler.call(this, type, file)
|
||||
}, { wait: opts.debounce })
|
||||
else
|
||||
handler= (type,file) => {this.handler.call(this,type,file)}
|
||||
handler = (type, file) => { this.handler.call(this, type, file) }
|
||||
|
||||
this._watcher.removeAllListeners()
|
||||
|
||||
|
@ -62,55 +62,57 @@ class Watcher extends Emitter {
|
|||
|
||||
// reset the error event since it got scrubbed
|
||||
this._watcher.on('error', error => {
|
||||
const msg ='chokidar watcher error'
|
||||
log.error({error:error, msg:msg})
|
||||
this.emit('error',msg,error)
|
||||
const msg = 'chokidar watcher error'
|
||||
log.error({ error: error, msg: msg })
|
||||
this.emit('error', msg, error)
|
||||
})
|
||||
}
|
||||
|
||||
async start(opts={}) {
|
||||
if(this._watching) {
|
||||
async start(opts = {}) {
|
||||
if (this._watching) {
|
||||
log.warn(`watching aleady running for ${opts.source || this.opts.source}`)
|
||||
return false
|
||||
}
|
||||
if (!this._watcher) opts = await this._init(opts)
|
||||
if (this._ready) {
|
||||
this.emit('ready', true, opts)
|
||||
log.trace({watching:this._watcher.getWatched(),msg:'initial files watched'})
|
||||
log.trace({ watching: this._watcher.getWatched(), msg: 'initial files watched' })
|
||||
log.info(`now watching ${opts.source || this.opts.source}`)
|
||||
if (this.registerHandler(opts)) {
|
||||
log.fatal('watcher was not initialzed so could not register handler')
|
||||
return new Error('watcher was not initialzed so could not register handler')
|
||||
}
|
||||
this._watching = true
|
||||
this.emit('watching',true,opts)
|
||||
this.emit('watching', true, opts)
|
||||
} else {
|
||||
const msg ='watcher is not ready to start, check options and try again'
|
||||
const msg = 'watcher is not ready to start, check options and try again'
|
||||
log.fatal(msg)
|
||||
this.emit('error',msg)
|
||||
this.emit('error', msg)
|
||||
return new Error('not ready to start check configuration options')
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
if(this._watching) {
|
||||
if (this._watching) {
|
||||
this._watching = false
|
||||
this._watcher.close()
|
||||
this.emit('watching',false)
|
||||
this.emit('watching', false)
|
||||
}
|
||||
else log.warn('not watching, nothing to stop')
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.stop()
|
||||
this._watcher.removeAllListeners()
|
||||
delete(this._watcher)
|
||||
this._ready=false
|
||||
this.emit('ready',false)
|
||||
if (this._watcher) {
|
||||
this.stop()
|
||||
this._watcher.removeAllListeners()
|
||||
delete (this._watcher)
|
||||
} else log.warn('no watcher started nothing to remove')
|
||||
this._ready = false
|
||||
this.emit('ready', false)
|
||||
}
|
||||
|
||||
async restart(opts,force) {
|
||||
if (typeof opts ==='boolean') {force=opts,opts={}}
|
||||
async restart(opts, force) {
|
||||
if (typeof opts === 'boolean') { force = opts, opts = {} }
|
||||
this.stop()
|
||||
await this.start(opts)
|
||||
}
|
||||
|
@ -121,37 +123,37 @@ class Watcher extends Emitter {
|
|||
|
||||
// private methods
|
||||
|
||||
async _init(opts={}) {
|
||||
async _init(opts = {}) {
|
||||
if (!opts.overwrite) {
|
||||
await this._fetchIgnoreLists(this.opts.excludeFrom)
|
||||
await this._fetchIgnoreLists(this.opts.ignoreList)
|
||||
}
|
||||
await this._fetchIgnoreLists(opts.excludeFrom,opts.overwrite)
|
||||
await this._fetchIgnoreLists(opts.ignoreList,opts.overwrite)
|
||||
await this._fetchIgnoreLists(opts.excludeFrom, opts.overwrite)
|
||||
await this._fetchIgnoreLists(opts.ignoreList, opts.overwrite)
|
||||
if (!opts.ignored) opts.ignored = []
|
||||
opts.ignored = Array.isArray(opts.ignored) ? opts.ignored : opts.ignored.split(',')
|
||||
opts.ignored = opts.overwrite ? opts.ignored : [...this._ignored,...opts.ignored]
|
||||
opts = Object.assign({},this.opts,opts) // now that ingnore arrays are dealt with merge options
|
||||
opts.ignored = opts.overwrite ? opts.ignored : [...this._ignored, ...opts.ignored]
|
||||
opts = Object.assign({}, this.opts, opts) // now that ingnore arrays are dealt with merge options
|
||||
return new Promise(async (resolve, reject) => {
|
||||
log.debug({options:opts, msg:'intializing watch with options'})
|
||||
log.debug({ options: opts, msg: 'intializing watch with options' })
|
||||
if (opts.source) {
|
||||
// create chokidar watcher
|
||||
this._watcher = watch(opts.source,opts)
|
||||
this._watcher = watch(opts.source, opts)
|
||||
this._watcher.once('error', error => {
|
||||
log.error({error:error, msg:'Watcher error'})
|
||||
reject({error:error, msg:'Watcher error'})
|
||||
log.error({ error: error, msg: 'Watcher error' })
|
||||
reject({ error: error, msg: 'Watcher error' })
|
||||
})
|
||||
this._watcher.once('ready', () => {
|
||||
clearTimeout(readyTimeout)
|
||||
log.info('initial scan sucessful, ready to start')
|
||||
this._ready=true
|
||||
this._ready = true
|
||||
resolve(opts)
|
||||
})
|
||||
log.debug(`initial scanning, timeout in ${this.timeout}ms`)
|
||||
let readyTimeout = setTimeout(() =>{
|
||||
log.fatal({options:opts, timeout:this.timeout, msg:'Timeout: unable to complete initial scan'})
|
||||
let readyTimeout = setTimeout(() => {
|
||||
log.fatal({ options: opts, timeout: this.timeout, msg: 'Timeout: unable to complete initial scan' })
|
||||
reject('timeout during initial scan, maybe increase ready timeout')
|
||||
},this.timeout)
|
||||
}, this.timeout)
|
||||
}
|
||||
else {
|
||||
log.fatal('MUST provide a source directory(s) option to watch')
|
||||
|
@ -160,11 +162,11 @@ class Watcher extends Emitter {
|
|||
})
|
||||
}
|
||||
|
||||
async _fetchIgnoreLists(lists,overwrite) {
|
||||
if (typeof lists === 'string') lists=[lists]
|
||||
async _fetchIgnoreLists(lists, overwrite) {
|
||||
if (typeof lists === 'string') lists = [lists]
|
||||
if (!Array.isArray(lists)) return // no lists
|
||||
let ignored = await readIgnoreLists(lists)
|
||||
this._ignored = overwrite ? ignored : [...this._ignored,...ignored]
|
||||
this._ignored = overwrite ? ignored : [...this._ignored, ...ignored]
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,21 +174,21 @@ class Watcher extends Emitter {
|
|||
} //end class
|
||||
|
||||
// default handler
|
||||
function _handler (type, f) {
|
||||
function _handler(type, f) {
|
||||
log.debug(`file ${f} was ${type}`)
|
||||
const fname = path.basename(f)
|
||||
if ( fname.toLowerCase() === 'package.json' && path.dirname(f)=== this.opts.source.replace(/\/$/, ''))
|
||||
if (type !=='modified') {
|
||||
if (fname.toLowerCase() === 'package.json' && path.dirname(f) === this.opts.source.replace(/\/$/, ''))
|
||||
if (type !== 'modified') {
|
||||
const msg = `a package.json in root of ${this.opts.source} was added or removed`
|
||||
log.warning(msg)
|
||||
this.emit('warning',f,msg)
|
||||
this.emit('warning', f, msg)
|
||||
return
|
||||
} else{
|
||||
} else {
|
||||
this.emit('install', f)
|
||||
}
|
||||
// user might want to run debounce on the listener for this event
|
||||
log.debug({file:f, type:type, msg:'file system changed, emitting'})
|
||||
this.emit('changed', f,type)
|
||||
log.debug({ file: f, type: type, msg: 'file system changed, emitting' })
|
||||
this.emit('changed', f, type)
|
||||
} // end handler
|
||||
|
||||
export default Watcher
|
||||
|
|
Loading…
Reference in New Issue