/// /// /// import { EventEmitter } from "events"; import { Stats } from "fs"; import { Matcher, Pattern } from "./matcher"; /** * 表示一个文件系统监听器 * @description * 本监听器的设计目标是:只针对常见场景,提供轻量、高效、稳定的实现,确保占用 CPU 极低且占用内存极小 * * 1. 完全基于原生的 `fs.watch` 实现,低于 Node 10.12 版本不保证稳定性 * 2. 可监听文件或文件夹(同时监听子文件夹),可动态调整监听列表,但监听的根路径必须已存在且不能删除 * 3. 仅支持文件的增、删、改事件和文件夹的增、删事件,重命名操作会按先删除后创建处理 * 4. 文件软链和硬链始终会被替换为链接的目标路径,循环链接会引发错误 * 5. 在不支持 `fs.watch` 的系统(比如虚拟机)可开启 `usePolling`(基于原生 `fs.watchFile` 实现),但这会占用较高 CPU * * 如果以上不符合你的需求,请考虑使用 [chokidar](https://www.npmjs.com/package/chokidar) * * @example * const watcher = new FileSystemWatcher() * watcher.on("change", path => { console.log("Changed", path) }) * watcher.on("delete", path => { console.log("Deleted", path) }) * watcher.on("create", path => { console.log("Created", path) }) * watcher.add(process.cwd(), () => { console.log("Start Watching...") }) */ export declare class FileSystemWatcher extends EventEmitter { /** * 初始化新的监听器 * @param options 附加选项 */ constructor(options?: FileSystemWatcherOptions); /** 所有原生监听器对象,键为监听的路径,值为原生监听器对象 */ private readonly _watchers; /** * 添加要监听的文件或文件夹 * @param path 要添加的文件或文件夹路径 * @param callback 添加完成的回调函数,在回调执行前无法监听到文件的修改 * @param callback.error 如果添加成功则为空,否则为错误对象 */ add(path: string, callback?: (error: NodeJS.ErrnoException | null) => void): boolean; /** 判断是否强制使用轮询监听,轮询监听可以支持更多的文件系统,但会占用大量 CPU */ readonly usePolling: boolean; /** 获取或设置传递给原生监听器的选项 */ watchOptions: { /** 是否在监听时阻止进程退出 */ persistent: boolean; /** 是否使用原生的递归监听支持 */ recursive: boolean; /** 轮询的间隔毫秒数 */ interval: number; }; /** * 创建指定路径的原生监听器 * @param path 要监听的文件或文件夹路径 * @param initStats 是否初始化路径对应的状态 * @param callback 创建完成的回调函数,在回调执行前无法监听到文件的修改 * @param callback.error 如果创建成功则为空,否则为相关的错误 * @returns 返回监听器 */ private _createWatcher; /** * 创建指定路径的轮询监听器 * @param path 要监听的文件或文件夹路径 * @param initStats 是否初始化路径对应的状态 * @param callback 创建完成的回调函数,在回调执行前无法监听到文件的修改 * @param callback.error 如果创建成功则为空,否则为相关的错误 * @returns 返回监听器 */ private _createPollingWatcher; /** * 所有文件或文件夹状态,对象的键是路径 * - 如果路径是一个文件,则值为文件的最后修改时间戳 * - 如果路径是一个文件夹,则值为所有直接子文件和子文件夹的名称数组 */ private readonly _stats; /** 正在执行的异步任务数 */ private _pending; /** * 初始化指定文件或文件夹的状态 * @param path 要添加的文件或文件夹路径 * @param isFile 是否优先将路径作为文件处理 * @param callback 已添加完成的回调函数 * @param depth 遍历的深度 */ private _initStats; /** 通知所有异步任务已执行结束 */ private _emitReady; /** * 当所有异步任务已执行结束执行 */ protected onReady(): void; /** * 等待所有异步任务都完成后执行指定的回调函数 * @param callback 要执行的回调函数 */ ready(callback: () => void): void; /** 忽略匹配器 */ readonly ignoreMatcher: Matcher; /** * 判断是否忽略指定的路径 * @param path 要判断的文件或文件夹路径,路径的分隔符同操作系统 */ ignored(path: string): boolean; /** * 判断是否正在监听指定的文件或文件夹 * @param path 要判断的路径 */ isWatchingPath(path: string): boolean; /** 判断当前监听器是否正在监听 */ get isWatching(): boolean; /** * 移除指定路径的监听器 * @param path 要移除的文件或文件夹路径 * @param callback 移除完成后的回调函数 * @description 注意如果已监听路径所在的文件夹,移除操作将无效 */ remove(path: string, callback?: () => void): boolean; /** * 删除指定路径的原生监听器 * @param path 要删除监听的文件或文件夹路径 */ private _deleteWatcher; /** * 移除已添加的所有监听器 * @param callback 移除完成后的回调函数 */ close(callback?: () => void): void; /** 暂停更新的次数 */ private _pauseCount; /** 判断当前监听器是否已赞同触发事件 */ get paused(): boolean; /** 暂停触发监听事件 */ pause(): void; /** 恢复触发监听事件 */ resume(): void; /** 所有已更新但未处理的文件或文件夹路径 */ private _pendingUpdates; /** 是否正在使用 _pendingUpdates */ private _pendingUpdatesLocked; /** 等待处理更新的计时器 */ private _emitUpdatesTimer?; /** 获取或设置监听延时回调的毫秒数 */ delay: number; /** 判断或设置是否仅当文件的最后修改时间发生变化才触发更新 */ compareModifyTime: boolean; /** * 处理原生更改事件 * @param path 更改的文件或文件夹路径 */ protected handleWatchChange(path: string): void; /** 处理所有更新 */ private _emitUpdates; /** * 更新指定文件或文件夹的状态 * @param path 要更新的文件或文件夹路径 * @param isFile 是否优先将路径作为文件处理 * @param force 是否强制更新文件 * @param pendingUpdates 本次同时更新的所有路径,提供此参数可避免重复更新 */ private _emitUpdate; /** * 删除指定文件或文件夹 * @param path 要删除的文件或文件夹路径 * @param pendingUpdates 本次同时更新的所有路径,提供此参数可避免重复更新 */ private _emitDelete; /** 通知更新结束 */ private _endUpdate; /** * 当监听到文件夹创建后执行 * @param path 相关的文件夹路径 * @param entries 文件夹内的文件列表 */ protected onCreateDir(path: string, entries: string[]): void; /** * 当监听到文件夹删除后执行 * @param path 相关的文件夹路径 * @param prevEntries 文件夹被删除前的文件列表 */ protected onDeleteDir(path: string, prevEntries: string[]): void; /** * 当监听到文件创建后执行 * @param path 相关的文件路径 * @param stats 文件属性对象 */ protected onCreate(path: string, stats: Stats): void; /** * 当监听到文件修改后执行 * @param path 相关的文件路径 * @param stats 相关的文件属性对象 * @param prevWriteTime 文件的上一次修改时间戳 */ protected onChange(path: string, stats: Stats, prevWriteTime: number): void; /** * 当监听到文件删除后执行 * @param path 相关的文件路径 * @param prevWriteTime 文件被删除前最后一次的修改时间戳 */ protected onDelete(path: string, prevWriteTime: number): void; /** * 当监听发生错误后执行 * @param error 相关的错误对象 * @param path 原始监听的路径 */ protected onError(error: NodeJS.ErrnoException, path: string): void; } /** 表示监听器的附加选项 */ export interface FileSystemWatcherOptions { /** * 监听延时回调的毫秒数 * @description 设置一定的延时可以避免在短时间内重复处理相同的文件 * @default 2500 */ delay?: number; /** * 是否在监听时阻止进程退出 * @default true */ persistent?: boolean; /** * 是否强制使用轮询监听,轮询监听可以支持更多的文件系统,但会占用大量 CPU * @default process.platform !== "win32" && process.platform !== "darwin" && process.platform !== "linux" && process.platform !== "aix" */ usePolling?: boolean; /** * 轮询的间隔毫秒数 * @default 512 */ interval?: number; /** * 是否仅当文件的最后修改时间发生变化才触发更新 * @default false */ compareModifyTime?: boolean; /** * 指定监听时忽略哪些文件,可以是通配符或正则表达式 * @default [".DS_Store", "Desktop.ini", "Thumbs.db", "ehthumbs.db", "*~", "*.tmp", ".git", ".vs"] */ ignore?: Pattern; }