diff options
author | RaindropsSys <contact@minteck.org> | 2023-04-02 23:03:02 +0200 |
---|---|---|
committer | RaindropsSys <contact@minteck.org> | 2023-04-02 23:03:02 +0200 |
commit | 02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b (patch) | |
tree | 6d1dec61008998aadc6b69f7e750712794d99324 /includes/external/chvfs/node_modules/node-watch/lib/watch.js | |
parent | f559308a1b42a9036135d764374a8c007b7d70a9 (diff) | |
download | pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.tar.gz pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.tar.bz2 pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.zip |
Updated 35 files, added 11 files and deleted includes/components/search.inc (automated)
Diffstat (limited to 'includes/external/chvfs/node_modules/node-watch/lib/watch.js')
-rw-r--r-- | includes/external/chvfs/node_modules/node-watch/lib/watch.js | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/includes/external/chvfs/node_modules/node-watch/lib/watch.js b/includes/external/chvfs/node_modules/node-watch/lib/watch.js new file mode 100644 index 0000000..b3d6889 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/watch.js @@ -0,0 +1,530 @@ +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var events = require('events'); + +var hasNativeRecursive = require('./has-native-recursive'); +var is = require('./is'); + +var EVENT_UPDATE = 'update'; +var EVENT_REMOVE = 'remove'; + +var SKIP_FLAG = Symbol('skip'); + +function hasDup(arr) { + return arr.some(function(v, i, self) { + return self.indexOf(v) !== i; + }); +} + +function unique(arr) { + return arr.filter(function(v, i, self) { + return self.indexOf(v) === i; + }); +} + +// One level flat +function flat1(arr) { + return arr.reduce(function(acc, v) { + return acc.concat(v); + }, []); +} + +function assertEncoding(encoding) { + if (encoding && encoding !== 'buffer' && !Buffer.isEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); + } +} + +function guard(fn) { + if (is.func(fn)) { + return function(arg, action) { + if (fn(arg, false)) action(); + } + } + if (is.regExp(fn)) { + return function(arg, action) { + if (fn.test(arg)) action(); + } + } + return function(arg, action) { + action(); + } +} + +function composeMessage(names) { + return names.map(function(n) { + return is.exists(n) + ? [EVENT_UPDATE, n] + : [EVENT_REMOVE, n]; + }); +} + +function getMessages(cache) { + var filtered = unique(cache); + + // Saving file from an editor? If so, assuming the + // non-existed files in the cache are temporary files + // generated by an editor and thus be filtered. + var reg = /~$|^\.#|^##$/g; + var hasSpecialChar = cache.some(function(c) { + return reg.test(c); + }); + + if (hasSpecialChar) { + var dup = hasDup(cache.map(function(c) { + return c.replace(reg, ''); + })); + if (dup) { + filtered = filtered.filter(function(m) { + return is.exists(m); + }); + } + } + + return composeMessage(filtered); +} + +function debounce(info, fn) { + var timer, cache = []; + var encoding = info.options.encoding; + var delay = info.options.delay; + if (!is.number(delay)) { + delay = 200; + } + function handle() { + getMessages(cache).forEach(function(msg) { + msg[1] = Buffer.from(msg[1]); + if (encoding !== 'buffer') { + msg[1] = msg[1].toString(encoding); + } + fn.apply(null, msg); + }); + timer = null; + cache = []; + } + return function(rawEvt, name) { + cache.push(name); + if (!timer) { + timer = setTimeout(handle, delay); + } + } +} + +function createDupsFilter() { + var memo = {}; + return function(fn) { + return function(evt, name) { + memo[evt + name] = [evt, name]; + setTimeout(function() { + Object.keys(memo).forEach(function(n) { + fn.apply(null, memo[n]); + }); + memo = {}; + }); + } + } +} + +function getSubDirectories(dir, fn, done = function() {}) { + if (is.directory(dir)) { + fs.readdir(dir, function(err, all) { + if (err) { + // don't throw permission errors. + if (/^(EPERM|EACCES)$/.test(err.code)) { + console.warn('Warning: Cannot access %s.', dir); + } else { + throw err; + } + } + else { + all.forEach(function(f) { + var sdir = path.join(dir, f); + if (is.directory(sdir)) fn(sdir); + }); + done(); + } + }); + } else { + done(); + } +} + +function semaphore(final) { + var counter = 0; + return function start() { + counter++; + return function stop() { + counter--; + if (counter === 0) final(); + }; + }; +} + +function nullCounter() { + return function nullStop() {}; +} + +function shouldNotSkip(filePath, filter) { + // watch it only if the filter is not function + // or not being skipped explicitly. + return !is.func(filter) || filter(filePath, SKIP_FLAG) !== SKIP_FLAG; +} + +var deprecationWarning = util.deprecate( + function() {}, + '(node-watch) First param in callback function\ + is replaced with event name since 0.5.0, use\ + `(evt, filename) => {}` if you want to get the filename' +); + +function Watcher() { + events.EventEmitter.call(this); + this.watchers = {}; + this._isReady = false; + this._isClosed = false; +} + +util.inherits(Watcher, events.EventEmitter); + +Watcher.prototype.expose = function() { + var expose = {}; + var self = this; + var methods = [ + 'on', 'emit', 'once', + 'close', 'isClosed', + 'listeners', 'setMaxListeners', 'getMaxListeners', + 'getWatchedPaths' + ]; + methods.forEach(function(name) { + expose[name] = function() { + return self[name].apply(self, arguments); + } + }); + return expose; +} + +Watcher.prototype.isClosed = function() { + return this._isClosed; +} + +Watcher.prototype.close = function(fullPath) { + var self = this; + if (fullPath) { + var watcher = this.watchers[fullPath]; + if (watcher && watcher.close) { + watcher.close(); + delete self.watchers[fullPath]; + } + getSubDirectories(fullPath, function(fpath) { + self.close(fpath); + }); + } + else { + Object.keys(self.watchers).forEach(function(fpath) { + var watcher = self.watchers[fpath]; + if (watcher && watcher.close) { + watcher.close(); + } + }); + this.watchers = {}; + } + // Do not close the Watcher unless all child watchers are closed. + // https://github.com/yuanchuan/node-watch/issues/75 + if (is.emptyObject(self.watchers)) { + // should emit once + if (!this._isClosed) { + this._isClosed = true; + process.nextTick(emitClose, this); + } + } +} + +Watcher.prototype.getWatchedPaths = function(fn) { + if (is.func(fn)) { + var self = this; + if (self._isReady) { + fn(Object.keys(self.watchers)); + } else { + self.on('ready', function() { + fn(Object.keys(self.watchers)); + }); + } + } +} + +function emitReady(self) { + if (!self._isReady) { + self._isReady = true; + // do not call emit for 'ready' until after watch() has returned, + // so that consumer can call on(). + process.nextTick(function () { + self.emit('ready'); + }); + } +} + +function emitClose(self) { + self.emit('close'); +} + +Watcher.prototype.add = function(watcher, info) { + var self = this; + info = info || { fpath: '' }; + var watcherPath = path.resolve(info.fpath); + this.watchers[watcherPath] = watcher; + + // Internal callback for handling fs.FSWatcher 'change' events + var internalOnChange = function(rawEvt, rawName) { + if (self.isClosed()) { + return; + } + + // normalise lack of name and convert to full path + var name = rawName; + if (is.nil(name)) { + name = ''; + } + name = path.join(info.fpath, name); + + if (info.options.recursive) { + hasNativeRecursive(function(has) { + if (!has) { + var fullPath = path.resolve(name); + // remove watcher on removal + if (!is.exists(name)) { + self.close(fullPath); + } + // watch new created directory + else { + var shouldWatch = is.directory(name) + && !self.watchers[fullPath] + && shouldNotSkip(name, info.options.filter); + + if (shouldWatch) { + self.watchDirectory(name, info.options); + } + } + } + }); + } + + handlePublicEvents(rawEvt, name); + }; + + // Debounced based on the 'delay' option + var handlePublicEvents = debounce(info, function (evt, name) { + // watch single file + if (info.compareName) { + if (info.compareName(name)) { + self.emit('change', evt, name); + } + } + // watch directory + else { + var filterGuard = guard(info.options.filter); + filterGuard(name, function() { + if (self.flag) self.flag = ''; + else self.emit('change', evt, name); + }); + } + }); + + watcher.on('error', function(err) { + if (self.isClosed()) { + return; + } + if (is.windows() && err.code === 'EPERM') { + watcher.emit('change', EVENT_REMOVE, info.fpath && ''); + self.flag = 'windows-error'; + self.close(watcherPath); + } else { + self.emit('error', err); + } + }); + + watcher.on('change', internalOnChange); +} + +Watcher.prototype.watchFile = function(file, options, fn) { + var parent = path.join(file, '../'); + var opts = Object.assign({}, options, { + // no filter for single file + filter: null, + encoding: 'utf8' + }); + + // no need to watch recursively + delete opts.recursive; + + var watcher = fs.watch(parent, opts); + this.add(watcher, { + type: 'file', + fpath: parent, + options: Object.assign({}, opts, { + encoding: options.encoding + }), + compareName: function(n) { + return is.samePath(n, file); + } + }); + + if (is.func(fn)) { + if (fn.length === 1) deprecationWarning(); + this.on('change', fn); + } +} + +Watcher.prototype.watchDirectory = function(dir, options, fn, counter = nullCounter) { + var self = this; + var done = counter(); + hasNativeRecursive(function(has) { + // always specify recursive + options.recursive = !!options.recursive; + // using utf8 internally + var opts = Object.assign({}, options, { + encoding: 'utf8' + }); + if (!has) { + delete opts.recursive; + } + + // check if it's closed before calling watch. + if (self._isClosed) { + done(); + return self.close(); + } + + var watcher = fs.watch(dir, opts); + + self.add(watcher, { + type: 'dir', + fpath: dir, + options: options + }); + + if (is.func(fn)) { + if (fn.length === 1) deprecationWarning(); + self.on('change', fn); + } + + if (options.recursive && !has) { + getSubDirectories(dir, function(d) { + if (shouldNotSkip(d, options.filter)) { + self.watchDirectory(d, options, null, counter); + } + }, counter()); + } + + done(); + }); +} + +function composeWatcher(watchers) { + var watcher = new Watcher(); + var filterDups = createDupsFilter(); + var counter = watchers.length; + + watchers.forEach(function(w) { + w.on('change', filterDups(function(evt, name) { + watcher.emit('change', evt, name); + })); + w.on('error', function(err) { + watcher.emit('error', err); + }); + w.on('ready', function() { + if (!(--counter)) { + emitReady(watcher); + } + }); + }); + + watcher.close = function() { + watchers.forEach(function(w) { + w.close(); + }); + process.nextTick(emitClose, watcher); + } + + watcher.getWatchedPaths = function(fn) { + if (is.func(fn)) { + var promises = watchers.map(function(w) { + return new Promise(function(resolve) { + w.getWatchedPaths(resolve); + }); + }); + Promise.all(promises).then(function(result) { + var ret = unique(flat1(result)); + fn(ret); + }); + } + } + + return watcher.expose(); +} + +function watch(fpath, options, fn) { + var watcher = new Watcher(); + + if (is.buffer(fpath)) { + fpath = fpath.toString(); + } + + if (!is.array(fpath) && !is.exists(fpath)) { + watcher.emit('error', + new Error(fpath + ' does not exist.') + ); + } + + if (is.string(options)) { + options = { + encoding: options + } + } + + if (is.func(options)) { + fn = options; + options = {}; + } + + if (arguments.length < 2) { + options = {}; + } + + if (options.encoding) { + assertEncoding(options.encoding); + } else { + options.encoding = 'utf8'; + } + + if (is.array(fpath)) { + if (fpath.length === 1) { + return watch(fpath[0], options, fn); + } + var filterDups = createDupsFilter(); + return composeWatcher(unique(fpath).map(function(f) { + var w = watch(f, options); + if (is.func(fn)) { + w.on('change', filterDups(fn)); + } + return w; + })); + } + + if (is.file(fpath)) { + watcher.watchFile(fpath, options, fn); + emitReady(watcher); + } + + else if (is.directory(fpath)) { + var counter = semaphore(function () { + emitReady(watcher); + }); + watcher.watchDirectory(fpath, options, fn, counter); + } + + return watcher.expose(); +} + +module.exports = watch; +module.exports.default = watch; |