import { FSWatcher, watch } from 'fs'; import { promises } from 'fs'; import event from 'events'; const readdir = promises.readdir; interface DiffWatcherEvent{ 'create':(filename:string)=>void, 'delete':(filename:string)=>void, 'change':(prev_filename:string,cur_filename:string)=>void, } export interface IDiffWatcher extends event.EventEmitter { on(event:U,listener:DiffWatcherEvent[U]): this; emit(event:U,...arg:Parameters): boolean; readonly path: string; } export class CommonDiffWatcher extends event.EventEmitter implements IDiffWatcher{ on(event:U,listener:DiffWatcherEvent[U]): this{ return super.on(event,listener); } emit(event:U,...arg:Parameters): boolean{ return super.emit(event,...arg); } private _path:string; private _watcher: FSWatcher|null; constructor(path:string){ super(); this._path = path; this._watcher = null; } public get path(){ return this._path; } /** * setup * @argument initial_filenames filename in path */ async setup(initial_filenames:string[]){ const cur = (await readdir(this._path,{ encoding:"utf8", withFileTypes: true, })).filter(x=>x.isFile).map(x=>x.name); //Todo : reduce O(nm) to O(n+m) using hash map. let added = cur.filter(x => !initial_filenames.includes(x)); let deleted = initial_filenames.filter(x=>!cur.includes(x)); for (const iterator of added) { this.emit('create',iterator); } for (const iterator of deleted){ this.emit('delete',iterator); } } watch():FSWatcher{ this._watcher = watch(this._path,{persistent: true, recursive:false},async (eventType,filename)=>{ if(eventType === "rename"){ const cur = (await readdir(this._path,{ encoding:"utf8", withFileTypes: true, })).filter(x=>x.isFile).map(x=>x.name); //add if(cur.includes(filename)){ this.emit('create',filename); } else{ this.emit('delete',filename) } } }); return this._watcher; } watchClose(){ this._watcher?.close() } }