import*as l from"chokidar";import h from"path";import*as p from"node:fs/promises";import{createHash as m}from"node:crypto";import{slash as n}from"../../utils/path/slash.js";import{logger as d}from"../tools/notifiers/logger.js";import{sha1 as u}from"../utils/crypto/sha1.js";import{debouncedEmit as g}from"./utils/debounced-emit.js";import{trackAccessStore as r}from"./utils/async-storage.js";import{removeBom as w}from"./utils/string-utils.js";class R{cwd;ignored;filesList=new Map;watcher;#t=new Map;#e=[];constructor(t,e=[]){this.cwd=t,this.ignored=e,this.watcher=this.#s()}get ready(){return this.watcher.then(()=>!0)}getFileInfo(t){return this.filesList.get(t)}watch(t){this.#e.push(t)}async dispose(){(await this.watcher).close()}exists(t){const e=this.filesList.has(t);return r.getStore()?.push({type:"exists",path:t,hash:e?"t":"f"}),e}async read(t,e="utf-8"){try{let i=await p.readFile(h.join(this.cwd,t),e);i=w(i);const s=u(i);r.getStore()?.push({type:"read",path:t,hash:s});const a=this.filesList.get(t);return a&&(a.hash=s),i}catch(i){throw r.getStore()?.push({type:"read",path:t,hash:"error"}),i}}scan(t){const e=[],i=m("sha1");this.filesList.forEach(a=>{(!t||t.test(a.relativePath))&&(e.push(a),i.update(a.relativePath))});const s=i.digest("base64");return this.#t.set(t,s),r.getStore()?.push({type:"scan",hash:s,pattern:t}),e}emitCodeUpdated(){this.emit({event:"code-updated"})}addVirtualFile(t,e){this.filesList.set(t,{relativePath:t,realRelativePath:e.realRelativePath,hash:e.hash,isVirtual:!0}),r.getStore()?.push({type:"read",path:t,hash:e.hash??""})}getPatternScanHash(t){return this.#t.get(t)}emit=g(async t=>{for(const e of t)switch(e.event){case"add":this.filesList.set(e.path,{relativePath:e.path,realRelativePath:e.path,hash:void 0,isVirtual:!1});for(const s of this.#t.keys())s&&s.test(e.path)&&this.#t.set(s,void 0),s||this.#t.set(s,void 0);break;case"change":const i=this.filesList.get(e.path);i&&(i.hash=void 0);break;case"unlink":this.filesList.delete(e.path);for(const s of this.#t.keys())s&&s.test(e.path)&&this.#t.delete(s),s||this.#t.delete(s);break}for(const e of this.#e)await e(t)});async#s(){return d.startTiming("init-fs"),new Promise((t,e)=>{const i=l.watch(this.cwd,{usePolling:!1,ignoreInitial:!0,ignored:[/(\/.git\/|\/node_modules\/|@theme)/,h.join(this.cwd,"public"),h.join(this.cwd,"README.md"),...this.ignored]});i.on("ready",()=>{this.filesList=v(i.getWatched(),this.cwd),t(i),d.infoTime("init-fs","File system scan completed")}).on("error",e).on("add",(s,a)=>{this.emit({event:"add",path:n(h.relative(this.cwd,s)),stats:a})}).on("change",(s,a)=>{this.emit({event:"change",path:n(h.relative(this.cwd,s)),stats:a})}).on("unlink",s=>{this.emit({event:"unlink",path:n(h.relative(this.cwd,s))})})})}}function v(o,t){const e=new Map;for(const i of Object.keys(o))for(const s of o[i]){const a=h.join(i,s);if(o[a])continue;const f=n(h.dirname(h.relative(t,a))),c=h.posix.join(f,s);e.set(c,{relativePath:c,realRelativePath:c,isVirtual:!1,hash:void 0})}return e}export{R as Fs};
