This commit is contained in:
Jacob Truman 2026-05-22 23:09:03 +01:00 committed by GitHub
commit 2a93b3fdcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 18 additions and 8 deletions

View file

@ -67,7 +67,8 @@ class FolderWatcher extends EventEmitter {
renameTimeout: 2000, renameTimeout: 2000,
recursive: true, recursive: true,
ignoreInitial: true, ignoreInitial: true,
persistent: true persistent: true,
followSymlinks: true
}) })
watcher watcher
.on('add', (path) => { .on('add', (path) => {

View file

@ -71,13 +71,13 @@ const Utils = {
poll: (targetPath, timeout = constants_1.POLLING_TIMEOUT) => { poll: (targetPath, timeout = constants_1.POLLING_TIMEOUT) => {
return ripstat_1.default(targetPath, timeout).catch(Utils.lang.noop); return ripstat_1.default(targetPath, timeout).catch(Utils.lang.noop);
}, },
readdir: async (rootPath, ignore, depth = Infinity, signal, readdirMap) => { readdir: async (rootPath, ignore, depth = Infinity, signal, readdirMap, followSymlinks = false) => {
if (readdirMap && depth === 1 && rootPath in readdirMap) { // Reusing cached data if (readdirMap && depth === 1 && rootPath in readdirMap) { // Reusing cached data
const result = readdirMap[rootPath]; const result = readdirMap[rootPath];
return [result.directories, result.files]; return [result.directories, result.files];
} }
else { // Retrieving fresh data else { // Retrieving fresh data
const result = await tiny_readdir_1.default(rootPath, { depth, ignore, signal }); const result = await tiny_readdir_1.default(rootPath, { depth, ignore, signal, followSymlinks });
return [result.directories, result.files]; return [result.directories, result.files];
} }
} }

View file

@ -91,7 +91,7 @@ class WatcherHandler {
var _a, _b; var _a, _b;
if (isInitial) if (isInitial)
return events; return events;
const depth = this.options.recursive ? (_a = this.options.depth) !== null && _a !== void 0 ? _a : constants_1.DEPTH : Math.min(1, (_b = this.options.depth) !== null && _b !== void 0 ? _b : constants_1.DEPTH), [directories, files] = await utils_1.default.fs.readdir(targetPath, this.options.ignore, depth, this.watcher._closeSignal), targetSubPaths = [...directories, ...files]; const depth = this.options.recursive ? (_a = this.options.depth) !== null && _a !== void 0 ? _a : constants_1.DEPTH : Math.min(1, (_b = this.options.depth) !== null && _b !== void 0 ? _b : constants_1.DEPTH), [directories, files] = await utils_1.default.fs.readdir(targetPath, this.options.ignore, depth, this.watcher._closeSignal, undefined, this.options.followSymlinks), targetSubPaths = [...directories, ...files];
await Promise.all(targetSubPaths.map(targetSubPath => { await Promise.all(targetSubPaths.map(targetSubPath => {
if (this.watcher.isIgnored(targetSubPath, this.options.ignore)) if (this.watcher.isIgnored(targetSubPath, this.options.ignore))
return; return;
@ -229,7 +229,7 @@ class WatcherHandler {
await this.onWatcherEvent("change" /* CHANGE */, this.filePath, isInitial); await this.onWatcherEvent("change" /* CHANGE */, this.filePath, isInitial);
} }
else { // Multiple initial paths else { // Multiple initial paths
const depth = this.options.recursive && (constants_1.HAS_NATIVE_RECURSION && this.options.native !== false) ? (_a = this.options.depth) !== null && _a !== void 0 ? _a : constants_1.DEPTH : Math.min(1, (_b = this.options.depth) !== null && _b !== void 0 ? _b : constants_1.DEPTH), [directories, files] = await utils_1.default.fs.readdir(this.folderPath, this.options.ignore, depth, this.watcher._closeSignal, this.options.readdirMap), targetPaths = [this.folderPath, ...directories, ...files]; const depth = this.options.recursive && (constants_1.HAS_NATIVE_RECURSION && this.options.native !== false) ? (_a = this.options.depth) !== null && _a !== void 0 ? _a : constants_1.DEPTH : Math.min(1, (_b = this.options.depth) !== null && _b !== void 0 ? _b : constants_1.DEPTH), [directories, files] = await utils_1.default.fs.readdir(this.folderPath, this.options.ignore, depth, this.watcher._closeSignal, this.options.readdirMap, this.options.followSymlinks), targetPaths = [this.folderPath, ...directories, ...files];
await Promise.all(targetPaths.map(targetPath => { await Promise.all(targetPaths.map(targetPath => {
if (this.watcher._poller.stats.has(targetPath)) if (this.watcher._poller.stats.has(targetPath))
return; // Already polled return; // Already polled

View file

@ -199,7 +199,7 @@ module.exports.recurseFiles = async (path, relPathToReplace = null) => {
ignoreFolders: true, ignoreFolders: true,
extensions: true, extensions: true,
deep: true, deep: true,
realPath: true, realPath: false,
normalizePath: false normalizePath: false
} }
let list = await rra.list(path, options) let list = await rra.list(path, options)
@ -517,7 +517,15 @@ module.exports.getDirectoriesInPath = async (dirPath, level) => {
Logger.debug(`Failed to lstat "${fullPath}"`, error) Logger.debug(`Failed to lstat "${fullPath}"`, error)
return null return null
}) })
if (!lstat?.isDirectory()) return null if (!lstat) return null
let isDir = lstat.isDirectory()
if (!isDir && lstat.isSymbolicLink()) {
// Follow symlink to check if target is a directory
const targetStat = await fs.stat(fullPath).catch(() => null)
isDir = targetStat?.isDirectory() ?? false
}
if (!isDir) return null
return { return {
path: this.filePathToPOSIX(fullPath), path: this.filePathToPOSIX(fullPath),

View file

@ -66,7 +66,8 @@ describe('fileUtils', () => {
// Stub fs.readdir // Stub fs.readdir
readdirStub = sinon.stub(fs, 'readdir') readdirStub = sinon.stub(fs, 'readdir')
readdirStub.callsFake((path, callback) => { readdirStub.callsFake((path, callback) => {
const contents = mockDirContents.get(path) const normalizedPath = path.replace(/\/+$/, '')
const contents = mockDirContents.get(normalizedPath)
if (contents) { if (contents) {
callback(null, contents) callback(null, contents)
} else { } else {