fs-fixture
Version:
Easily create test fixtures at a temporary file-system path
2 lines (1 loc) • 3.98 kB
JavaScript
;var v=Object.defineProperty;var o=(r,e)=>v(r,"name",{value:e,configurable:!0});var y=require("node:fs/promises"),c=require("node:path"),F=require("node:url"),b=require("node:fs"),j=require("node:os");const w=o(async(r,e)=>{try{await r.unlink(e);return}catch(i){if(D(i))return}const t=await r.readdir(e,{withFileTypes:!0});await Promise.all(t.map(i=>{const n=c.join(e,i.name);return i.isDirectory()?w(r,n):r.unlink(n)})),await r.rmdir(e)},"recursiveRm"),D=o(r=>r instanceof Error&&"code"in r&&r.code==="ENOENT","isEnoent");typeof Symbol.asyncDispose!="symbol"&&Object.defineProperty(Symbol,"asyncDispose",{configurable:!1,enumerable:!1,writable:!1,value:Symbol.for("asyncDispose")});class x{static{o(this,"FsFixture")}path;fs;constructor(e,t){this.path=e,this.fs=t??y}getPath(...e){return c.join(this.path,...e)}exists(e=""){return this.fs.access(this.getPath(e)).then(()=>!0,()=>!1)}rm(e=""){const t=this.getPath(e);if(this.fs.rm)return this.fs.rm(t,{recursive:!0,force:!0});if(!this.fs.unlink||!this.fs.rmdir)throw new Error("rm() requires the fs API to support rm(), or unlink() + rmdir()");return w(this.fs,t)}cp(e,t,i){if(!this.fs.cp)throw new Error("cp() requires the fs API to support cp()");return t?(t.endsWith("/")||t.endsWith(c.sep))&&(t+=c.basename(e)):t=c.basename(e),this.fs.cp(e,this.getPath(t),i)}mkdir(e){return this.fs.mkdir(this.getPath(e),{recursive:!0})}mv(e,t){return this.fs.rename(this.getPath(e),this.getPath(t))}readFile=o(((e,t)=>this.fs.readFile(this.getPath(e),t)),"readFile");readdir=o(((e,t)=>this.fs.readdir(this.getPath(e||""),t)),"readdir");writeFile=o(((e,t,...i)=>this.fs.writeFile(this.getPath(e),t,...i)),"writeFile");async readJson(e){const t=await this.readFile(e,"utf8");return JSON.parse(t)}writeJson(e,t,i=2){return this.writeFile(e,JSON.stringify(t,null,i))}async[Symbol.asyncDispose](){await this.rm()}}const T=b.realpathSync(j.tmpdir());class m{static{o(this,"PathBase")}path;constructor(e){this.path=e}}class d extends m{static{o(this,"Directory")}}class p extends m{static{o(this,"File")}content;constructor(e,t){super(e),this.content=t}}class h extends m{static{o(this,"Symlink")}target;type;constructor(e,t,i){super(i??""),this.target=e,this.type=t}}const g=o((r,e,t)=>{const i=[];for(const n in r){if(!Object.hasOwn(r,n))continue;const f=c.join(e,n);let a=r[n];if(typeof a=="function"){const l=Object.assign(Object.create(t),{filePath:f}),u=a(l);if(u instanceof h){const s=new h(u.target,u.type,f);i.push(s);continue}else a=u}if(typeof a=="string"||Buffer.isBuffer(a))i.push(new p(f,a));else if(a&&typeof a=="object"&&!Array.isArray(a))i.push(new d(f),...g(a,f,t));else throw new TypeError(`Invalid file content for path "${f}". Functions must return a string, Buffer, Symlink, or a nested FileTree object. Received: ${String(a)}`)}return i},"flattenFileTree");let k=0;const q=o(async(r,e)=>{const t=e?.fs??y,i=e?.tempDir?c.resolve(typeof e.tempDir=="string"?e.tempDir:F.fileURLToPath(e.tempDir)):T;e?.tempDir&&await t.mkdir(i,{recursive:!0});let n;if(t.mkdtemp?n=await t.mkdtemp(c.join(i,"fs-fixture-")):(k+=1,n=c.join(i,`fs-fixture-${process.pid}-${k}`),await t.mkdir(n,{recursive:!0})),r){if(typeof r=="string"){if(!t.cp)throw new TypeError("Template directory sources require the fs API to support cp()");await t.cp(r,n,{recursive:!0,filter:e?.templateFilter})}else if(typeof r=="object"){const a=g(r,n,{fixturePath:n,getPath:o((...s)=>c.join(n,...s),"getPath"),symlink:o((s,P)=>new h(s,P),"symlink")}),l=new Set;for(const s of a)s instanceof d?l.add(s.path):(s instanceof p||s instanceof h)&&l.add(c.dirname(s.path));if(await Promise.all(Array.from(l).map(s=>t.mkdir(s,{recursive:!0}))),a.some(s=>s instanceof h)&&!t.symlink)throw new TypeError("Symlinks require the fs API to support symlink()");await Promise.all(a.map(async s=>{s instanceof h?await t.symlink(s.target,s.path,s.type):s instanceof p&&await t.writeFile(s.path,s.content)}))}}return new x(n,e?.fs)},"createFixture");exports.createFixture=q;