From 02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b Mon Sep 17 00:00:00 2001 From: RaindropsSys Date: Sun, 2 Apr 2023 23:03:02 +0200 Subject: Updated 35 files, added 11 files and deleted includes/components/search.inc (automated) --- .../node-watch/lib/has-native-recursive.js | 115 +++++ .../chvfs/node_modules/node-watch/lib/is.js | 78 +++ .../chvfs/node_modules/node-watch/lib/watch.d.ts | 75 +++ .../chvfs/node_modules/node-watch/lib/watch.js | 530 +++++++++++++++++++++ 4 files changed, 798 insertions(+) create mode 100644 includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js create mode 100644 includes/external/chvfs/node_modules/node-watch/lib/is.js create mode 100644 includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts create mode 100644 includes/external/chvfs/node_modules/node-watch/lib/watch.js (limited to 'includes/external/chvfs/node_modules/node-watch/lib') diff --git a/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js b/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js new file mode 100644 index 0000000..19c1b88 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js @@ -0,0 +1,115 @@ +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var is = require('./is'); + +var IS_SUPPORT; +var TEMP_DIR = os.tmpdir && os.tmpdir() + || process.env.TMPDIR + || process.env.TEMP + || process.cwd(); + +function TempStack() { + this.stack = []; +} + +TempStack.prototype = { + create: function(type, base) { + var name = path.join(base, + 'node-watch-' + Math.random().toString(16).substr(2) + ); + this.stack.push({ name: name, type: type }); + return name; + }, + write: function(/* file */) { + for (var i = 0; i < arguments.length; ++i) { + fs.writeFileSync(arguments[i], ' '); + } + }, + mkdir: function(/* dirs */) { + for (var i = 0; i < arguments.length; ++i) { + fs.mkdirSync(arguments[i]); + } + }, + cleanup: function(fn) { + try { + var temp; + while ((temp = this.stack.pop())) { + var type = temp.type; + var name = temp.name; + if (type === 'file' && is.file(name)) { + fs.unlinkSync(name); + } + else if (type === 'dir' && is.directory(name)) { + fs.rmdirSync(name); + } + } + } + finally { + if (is.func(fn)) fn(); + } + } +}; + +var pending = false; + +module.exports = function hasNativeRecursive(fn) { + if (!is.func(fn)) { + return false; + } + if (IS_SUPPORT !== undefined) { + return fn(IS_SUPPORT); + } + + if (!pending) { + pending = true; + } + // check again later + else { + return setTimeout(function() { + hasNativeRecursive(fn); + }, 300); + } + + var stack = new TempStack(); + var parent = stack.create('dir', TEMP_DIR); + var child = stack.create('dir', parent); + var file = stack.create('file', child); + + stack.mkdir(parent, child); + + var options = { recursive: true }; + var watcher; + + try { + watcher = fs.watch(parent, options); + } catch (e) { + if (e.code == 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM') { + return fn(IS_SUPPORT = false); + } else { + throw e; + } + } + + if (!watcher) { + return false; + } + + var timer = setTimeout(function() { + watcher.close(); + stack.cleanup(function() { + fn(IS_SUPPORT = false); + }); + }, 200); + + watcher.on('change', function(evt, name) { + if (path.basename(file) === path.basename(name)) { + watcher.close(); + clearTimeout(timer); + stack.cleanup(function() { + fn(IS_SUPPORT = true); + }); + } + }); + stack.write(file); +} diff --git a/includes/external/chvfs/node_modules/node-watch/lib/is.js b/includes/external/chvfs/node_modules/node-watch/lib/is.js new file mode 100644 index 0000000..ebe0600 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/is.js @@ -0,0 +1,78 @@ +var fs = require('fs'); +var path = require('path'); +var os = require('os'); + +function matchObject(item, str) { + return Object.prototype.toString.call(item) + === '[object ' + str + ']'; +} + +function checkStat(name, fn) { + try { + return fn(name); + } catch (err) { + if (/^(ENOENT|EPERM|EACCES)$/.test(err.code)) { + if (err.code !== 'ENOENT') { + console.warn('Warning: Cannot access %s', name); + } + return false; + } + throw err; + } +} + +var is = { + nil: function(item) { + return item == null; + }, + array: function(item) { + return Array.isArray(item); + }, + emptyObject: function(item) { + for (var key in item) { + return false; + } + return true; + }, + buffer: function(item) { + return Buffer.isBuffer(item); + }, + regExp: function(item) { + return matchObject(item, 'RegExp'); + }, + string: function(item) { + return matchObject(item, 'String'); + }, + func: function(item) { + return typeof item === 'function'; + }, + number: function(item) { + return matchObject(item, 'Number'); + }, + exists: function(name) { + return fs.existsSync(name); + }, + file: function(name) { + return checkStat(name, function(n) { + return fs.statSync(n).isFile() + }); + }, + samePath: function(a, b) { + return path.resolve(a) === path.resolve(b); + }, + directory: function(name) { + return checkStat(name, function(n) { + return fs.statSync(n).isDirectory() + }); + }, + symbolicLink: function(name) { + return checkStat(name, function(n) { + return fs.lstatSync(n).isSymbolicLink(); + }); + }, + windows: function() { + return os.platform() === 'win32'; + } +}; + +module.exports = is; diff --git a/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts b/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts new file mode 100644 index 0000000..9eca5d4 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts @@ -0,0 +1,75 @@ +import { FSWatcher } from 'fs'; + +/** + * Watch for changes on `filename`, where filename is either a file or a directory. + * The second argument is optional. + * + * If `options` is provided as a string, it specifies the encoding. + * Otherwise `options` should be passed as an object. + * + * The listener callback gets two arguments, `(eventType, filePath)`, + * which is the same with `fs.watch`. + * `eventType` is either `update` or `remove`, + * `filePath` is the name of the file which triggered the event. + * + * @param {Filename} filename File or directory to watch. + * @param {Options|string} options + * @param {Function} callback + */ +declare function watch(pathName: PathName): Watcher; +declare function watch(pathName: PathName, options: Options) : Watcher; +declare function watch(pathName: PathName, callback: Callback): Watcher; +declare function watch(pathName: PathName, options: Options, callback: Callback): Watcher; + +type EventType = 'update' | 'remove'; +type Callback = (eventType: EventType, filePath: string) => any; +type PathName = string | Array; +type FilterReturn = boolean | symbol; + +type Options = { + /** + * Indicates whether the process should continue to run + * as long as files are being watched. + * @default true + */ + persistent ?: boolean; + + /** + * Indicates whether all subdirectories should be watched. + * @default false + */ + recursive ?: boolean; + + /** + * Specifies the character encoding to be used for the filename + * passed to the listener. + * @default 'utf8' + */ + encoding ?: string; + + /** + * Only files which pass this filter (when it returns `true`) + * will be sent to the listener. + */ + filter ?: RegExp | ((file: string, skip: symbol) => FilterReturn); + + /** + * Delay time of the callback function. + * @default 200 + */ + delay ?: number; +}; + +declare interface Watcher extends FSWatcher { + /** + * Returns `true` if the watcher has been closed. + */ + isClosed(): boolean; + + /** + * Returns all watched paths. + */ + getWatchedPaths(): Array; +} + +export default watch; 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; -- cgit