nl_tokens: watching directory recursive
pl_tokens: function watchRecursive ( dir , opts , onChange , cb , repeated ) { // cb(err, files) if ( arguments . length === 3 ) { cb = arguments [ 2 ] ; onChange = arguments [ 1 ] ; opts = { } ; } opts = object . extend ( { } , opts || { } , { includeRootDir : true } ) ; if ( typeof cb !== 'function' ) throw new Error ( 'Wrong arguments' ) ; var maxRepeats = 5 ; repeated = repeated || 0 ; // walk dir and setup watchers dir = walk ( dir , opts , function ( err , items ) { // sometimes, when setuping watch right after moving, or renaming "EPERM" error may occur, just wait and try again if ( err && err . code === 'EPERM' ) { if ( repeated < maxRepeats ) setTimeout ( function ( ) { watchRecursive ( dir , opts , onChange , cb , repeated + 1 ) ; } , 100 ) ; else cb ( new Error ( 'fsExt.watchRecursive: exploring folder failed' ) . cause ( err ) ) ; } else if ( err ) { cb ( new Error ( 'fsExt.watchRecursive: exploring folder failed' ) . cause ( err ) ) ; } else { watchDir ( dir , items , cb ) ; } } , opts . rootDir ) ; function watchDir ( dir , items , done ) { for ( var key in items ) { if ( <mask> [ key ] . isDir && ! _dirWatchers [ items [ key ] . fullPath ] ) { // avoid duplicite watchers // set dir watch try { var item = items [ key ] ; _dirWatchers [ item . fullPath ] = fs . watch ( item . fullPath , { persistent : opts . watchPersistent || false } ) . on ( 'change' , function ( op , fileName ) { var onChangeOpts = object . extend ( { } , opts , { rootDir : opts . rootDir || dir } ) , watcher = this ; watchRecursive ( watcher . fullPath , onChangeOpts , onChange , function ( err , descendants ) { if ( err && err . code === 'ENOENT' ) return ; else if ( err ) onChange ( new Error ( 'fsExt.watchRecursive onChange: setup nested watch failed' ) . cause ( err ) ) ; else { var changes = compareDirFiles ( watcher . id , watcher . children , descendants ) ; // remove watchers if whole folder is removed for ( var i = 0 ; i < changes . length ; i ++ ) { if ( changes [ i ] . event === 'removed' && changes [ i ] . file . isDir ) { delete _dirWatchers [ changes [ i ] . file . fullPath ] ; } } if ( changes . length ) onChange ( null , changes ) ; } } ) ; } ) . on ( 'error' , function ( err ) { this . close ( ) ; _dirWatchers [ this . fullPath ] = null ; } ) ; object . extend ( _dirWatchers [ item . fullPath ] , { children : getDirChildren ( item . id , items ) } , item ) ; } catch ( err ) { return done ( new Error ( 'fsExt.watchRecursive: setup watcher failed' ) . cause ( err ) ) ; } } } done ( null , items ) ; } }