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