fs-fixture 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +72 -4
- package/dist/index.d.mts +72 -4
- package/dist/index.mjs +1 -1
- package/package.json +2 -1
- package/skills/fs-fixture/SKILL.md +18 -0
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Simple API to create disposable test fixtures on disk. Tiny (`1.1 kB` gzipped) w
|
|
|
17
17
|
- 💾 Binary file support with Buffers
|
|
18
18
|
- 🎯 TypeScript-first with full type safety
|
|
19
19
|
- 🔄 File methods inherit types directly from Node.js `fs` module
|
|
20
|
+
- 🔌 Pluggable filesystem — use with @platformatic/vfs, memfs, or any `fs/promises`-compatible API
|
|
20
21
|
|
|
21
22
|
## Installation
|
|
22
23
|
|
|
@@ -185,6 +186,49 @@ const fixture = await createFixture({
|
|
|
185
186
|
})
|
|
186
187
|
```
|
|
187
188
|
|
|
189
|
+
> [!TIP]
|
|
190
|
+
> Path syntax also works for grouped prefixes, so you can keep related files together without repeating the shared path:
|
|
191
|
+
>
|
|
192
|
+
> ```ts
|
|
193
|
+
> await createFixture({
|
|
194
|
+
> 'file.js': 'import { a } from "my-pkg";',
|
|
195
|
+
>
|
|
196
|
+
> 'node_modules/my-pkg': {
|
|
197
|
+
> 'package.json': JSON.stringify({
|
|
198
|
+
> name: 'my-pkg',
|
|
199
|
+
> type: 'module',
|
|
200
|
+
> exports: './index.js'
|
|
201
|
+
> }),
|
|
202
|
+
> 'index.js': 'export const a = 1;'
|
|
203
|
+
> }
|
|
204
|
+
> })
|
|
205
|
+
> ```
|
|
206
|
+
|
|
207
|
+
### Custom filesystem
|
|
208
|
+
|
|
209
|
+
Pass any `fs/promises`-compatible API via the `fs` option to use a virtual filesystem instead of disk:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { create, MemoryProvider } from '@platformatic/vfs'
|
|
213
|
+
import { createFixture } from 'fs-fixture'
|
|
214
|
+
|
|
215
|
+
const fs = create(new MemoryProvider()).promises
|
|
216
|
+
const fixture = await createFixture({
|
|
217
|
+
'package.json': JSON.stringify({ name: 'test' }),
|
|
218
|
+
'src/index.js': 'export default 42'
|
|
219
|
+
}, { fs })
|
|
220
|
+
|
|
221
|
+
await fixture.readFile('src/index.js', 'utf8') // 'export default 42'
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Works with any library that implements the `fs/promises` API shape, including [@platformatic/vfs](https://github.com/platformatic/vfs), the future [`node:vfs`](https://github.com/nodejs/node/pull/61478), and [memfs](https://github.com/streamich/memfs).
|
|
225
|
+
|
|
226
|
+
> [!NOTE]
|
|
227
|
+
> With a custom fs, files only exist in that fs instance. Use `fixture.readFile()` or `fixture.fs` to access them — `fixture.path` is a virtual path that doesn't exist on the real disk.
|
|
228
|
+
|
|
229
|
+
> [!NOTE]
|
|
230
|
+
> Template directory sources (string paths) are not supported with custom filesystems because most virtual fs implementations lack recursive `cp`. Use a `FileTree` object instead.
|
|
231
|
+
|
|
188
232
|
## API
|
|
189
233
|
|
|
190
234
|
### `createFixture(source?, options?)`
|
|
@@ -195,6 +239,7 @@ Creates a temporary fixture directory and returns a `FsFixture` instance.
|
|
|
195
239
|
- `source` (optional): String path to template directory, or `FileTree` object defining the structure
|
|
196
240
|
- `options.tempDir` (optional): Custom temp directory. Defaults to `os.tmpdir()`
|
|
197
241
|
- `options.templateFilter` (optional): Filter function when copying from template directory
|
|
242
|
+
- `options.fs` (optional): Custom `fs/promises`-compatible API for virtual filesystem support
|
|
198
243
|
|
|
199
244
|
**Returns:** `Promise<FsFixture>`
|
|
200
245
|
|
|
@@ -210,6 +255,7 @@ const fixture = await createFixture({}, { tempDir: './custom-temp' })
|
|
|
210
255
|
| Method | Description |
|
|
211
256
|
|--------|-------------|
|
|
212
257
|
| `fixture.path` | Absolute path to the fixture directory |
|
|
258
|
+
| `fixture.fs` | The underlying `fs/promises` API used by the fixture |
|
|
213
259
|
| `getPath(...paths)` | Get absolute path to file/directory in fixture |
|
|
214
260
|
| `exists(path?)` | Check if file/directory exists |
|
|
215
261
|
| `rm(path?)` | Delete file/directory (or entire fixture if no path) |
|
|
@@ -241,6 +287,34 @@ type Api = {
|
|
|
241
287
|
```
|
|
242
288
|
</details>
|
|
243
289
|
|
|
290
|
+
<details>
|
|
291
|
+
<summary><strong>FsPromises</strong></summary>
|
|
292
|
+
|
|
293
|
+
The subset of `fs/promises` methods that custom filesystem implementations must provide:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
type FsPromises = {
|
|
297
|
+
// Required
|
|
298
|
+
readFile(path: string, options?): Promise<Buffer | string>
|
|
299
|
+
writeFile(path: string, data: string | Buffer, options?): Promise<void>
|
|
300
|
+
readdir(path: string, options?): Promise<string[] | Dirent[]>
|
|
301
|
+
mkdir(path: string, options?): Promise<string | undefined>
|
|
302
|
+
rename(oldPath: string, newPath: string): Promise<void>
|
|
303
|
+
access(path: string, mode?: number): Promise<void>
|
|
304
|
+
|
|
305
|
+
// Optional
|
|
306
|
+
rm?(path: string, options?): Promise<void>
|
|
307
|
+
unlink?(path: string): Promise<void>
|
|
308
|
+
rmdir?(path: string): Promise<void>
|
|
309
|
+
symlink?(target: string, path: string, type?: string): Promise<void>
|
|
310
|
+
cp?(source: string, destination: string, options?): Promise<void>
|
|
311
|
+
mkdtemp?(prefix: string): Promise<string>
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
If `rm` is not available, fs-fixture falls back to recursive removal using `readdir({ withFileTypes })` + `unlink` + `rmdir`. If `mkdtemp` is not available, fixture paths are generated with a counter.
|
|
316
|
+
</details>
|
|
317
|
+
|
|
244
318
|
## Related
|
|
245
319
|
|
|
246
320
|
### [manten](https://github.com/privatenumber/manten)
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";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;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,17 +1,69 @@
|
|
|
1
1
|
import { CopyOptions } from 'node:fs';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* A subset of `fs/promises` methods used by FsFixture.
|
|
6
|
+
* Compatible with Node.js `fs/promises`, `@platformatic/vfs`,
|
|
7
|
+
* `memfs`, and other fs-compatible implementations.
|
|
8
|
+
*
|
|
9
|
+
* Pass a custom implementation to `createFixture({ fs })`
|
|
10
|
+
* to use a virtual filesystem.
|
|
11
|
+
*/
|
|
12
|
+
type FsPromises = {
|
|
13
|
+
readFile: {
|
|
14
|
+
(path: string, options?: {
|
|
15
|
+
encoding?: null;
|
|
16
|
+
} | null): Promise<Buffer>;
|
|
17
|
+
(path: string, options: BufferEncoding | {
|
|
18
|
+
encoding: BufferEncoding;
|
|
19
|
+
}): Promise<string>;
|
|
20
|
+
};
|
|
21
|
+
writeFile(path: string, data: string | Buffer, options?: BufferEncoding | {
|
|
22
|
+
encoding?: BufferEncoding;
|
|
23
|
+
} | null): Promise<void>;
|
|
24
|
+
readdir: {
|
|
25
|
+
(path: string, options?: {
|
|
26
|
+
withFileTypes?: false;
|
|
27
|
+
}): Promise<string[]>;
|
|
28
|
+
(path: string, options: {
|
|
29
|
+
withFileTypes: true;
|
|
30
|
+
}): Promise<Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
isFile(): boolean;
|
|
33
|
+
isDirectory(): boolean;
|
|
34
|
+
}>>;
|
|
35
|
+
};
|
|
36
|
+
mkdir(path: string, options?: {
|
|
37
|
+
recursive?: boolean;
|
|
38
|
+
}): Promise<string | undefined>;
|
|
39
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
40
|
+
access(path: string, mode?: number): Promise<void>;
|
|
41
|
+
rm?(path: string, options?: {
|
|
42
|
+
recursive?: boolean;
|
|
43
|
+
force?: boolean;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
unlink?(path: string): Promise<void>;
|
|
46
|
+
rmdir?(path: string): Promise<void>;
|
|
47
|
+
symlink?(target: string, path: string, type?: string | null): Promise<void>;
|
|
48
|
+
cp?(source: string, destination: string, options?: {
|
|
49
|
+
recursive?: boolean;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
mkdtemp?(prefix: string): Promise<string>;
|
|
52
|
+
};
|
|
53
|
+
|
|
4
54
|
declare class FsFixture {
|
|
5
55
|
/**
|
|
6
56
|
* Path to the fixture directory.
|
|
7
57
|
*/
|
|
8
58
|
readonly path: string;
|
|
59
|
+
readonly fs: FsPromises;
|
|
9
60
|
/**
|
|
10
61
|
* Create a Fixture instance from a path. Does not create the fixture directory.
|
|
11
62
|
*
|
|
12
63
|
* @param fixturePath - The path to the fixture directory
|
|
64
|
+
* @param fsApi - Optional fs/promises-compatible API. Defaults to real node:fs/promises.
|
|
13
65
|
*/
|
|
14
|
-
constructor(fixturePath: string);
|
|
66
|
+
constructor(fixturePath: string, fsApi?: FsPromises);
|
|
15
67
|
/**
|
|
16
68
|
* Get the full path to a subpath in the fixture directory.
|
|
17
69
|
*
|
|
@@ -160,8 +212,8 @@ declare class PathBase {
|
|
|
160
212
|
type SymlinkType = 'file' | 'dir' | 'junction';
|
|
161
213
|
declare class Symlink extends PathBase {
|
|
162
214
|
readonly target: string;
|
|
163
|
-
readonly type?: SymlinkType
|
|
164
|
-
constructor(target: string, type?: SymlinkType
|
|
215
|
+
readonly type?: SymlinkType;
|
|
216
|
+
constructor(target: string, type?: SymlinkType, filePath?: string);
|
|
165
217
|
}
|
|
166
218
|
|
|
167
219
|
type ApiBase = {
|
|
@@ -196,6 +248,22 @@ type CreateFixtureOptions = {
|
|
|
196
248
|
* Return `true` to copy the item, `false` to ignore it.
|
|
197
249
|
*/
|
|
198
250
|
templateFilter?: FilterFunction;
|
|
251
|
+
/**
|
|
252
|
+
* Custom fs/promises-compatible API for fixture operations.
|
|
253
|
+
* Use this to create fixtures in a virtual filesystem instead of on disk.
|
|
254
|
+
*
|
|
255
|
+
* Required: readFile, writeFile, readdir (with withFileTypes),
|
|
256
|
+
* mkdir, rename, access.
|
|
257
|
+
* Optional: rm (or unlink + rmdir as fallback), symlink, cp, mkdtemp.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* import { create, MemoryProvider } from '@platformatic/vfs'
|
|
262
|
+
* const vfs = create(new MemoryProvider())
|
|
263
|
+
* const fixture = await createFixture({ 'file.txt': 'hi' }, { fs: vfs.promises })
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
fs?: FsPromises;
|
|
199
267
|
};
|
|
200
268
|
/**
|
|
201
269
|
* Create a temporary test fixture directory.
|
|
@@ -229,4 +297,4 @@ type CreateFixtureOptions = {
|
|
|
229
297
|
declare const createFixture: (source?: string | FileTree, options?: CreateFixtureOptions) => Promise<FsFixture>;
|
|
230
298
|
|
|
231
299
|
export { createFixture };
|
|
232
|
-
export type { CreateFixtureOptions, FileTree, FsFixtureType as FsFixture };
|
|
300
|
+
export type { CreateFixtureOptions, FileTree, FsFixtureType as FsFixture, FsPromises };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,69 @@
|
|
|
1
1
|
import { CopyOptions } from 'node:fs';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* A subset of `fs/promises` methods used by FsFixture.
|
|
6
|
+
* Compatible with Node.js `fs/promises`, `@platformatic/vfs`,
|
|
7
|
+
* `memfs`, and other fs-compatible implementations.
|
|
8
|
+
*
|
|
9
|
+
* Pass a custom implementation to `createFixture({ fs })`
|
|
10
|
+
* to use a virtual filesystem.
|
|
11
|
+
*/
|
|
12
|
+
type FsPromises = {
|
|
13
|
+
readFile: {
|
|
14
|
+
(path: string, options?: {
|
|
15
|
+
encoding?: null;
|
|
16
|
+
} | null): Promise<Buffer>;
|
|
17
|
+
(path: string, options: BufferEncoding | {
|
|
18
|
+
encoding: BufferEncoding;
|
|
19
|
+
}): Promise<string>;
|
|
20
|
+
};
|
|
21
|
+
writeFile(path: string, data: string | Buffer, options?: BufferEncoding | {
|
|
22
|
+
encoding?: BufferEncoding;
|
|
23
|
+
} | null): Promise<void>;
|
|
24
|
+
readdir: {
|
|
25
|
+
(path: string, options?: {
|
|
26
|
+
withFileTypes?: false;
|
|
27
|
+
}): Promise<string[]>;
|
|
28
|
+
(path: string, options: {
|
|
29
|
+
withFileTypes: true;
|
|
30
|
+
}): Promise<Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
isFile(): boolean;
|
|
33
|
+
isDirectory(): boolean;
|
|
34
|
+
}>>;
|
|
35
|
+
};
|
|
36
|
+
mkdir(path: string, options?: {
|
|
37
|
+
recursive?: boolean;
|
|
38
|
+
}): Promise<string | undefined>;
|
|
39
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
40
|
+
access(path: string, mode?: number): Promise<void>;
|
|
41
|
+
rm?(path: string, options?: {
|
|
42
|
+
recursive?: boolean;
|
|
43
|
+
force?: boolean;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
unlink?(path: string): Promise<void>;
|
|
46
|
+
rmdir?(path: string): Promise<void>;
|
|
47
|
+
symlink?(target: string, path: string, type?: string | null): Promise<void>;
|
|
48
|
+
cp?(source: string, destination: string, options?: {
|
|
49
|
+
recursive?: boolean;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
mkdtemp?(prefix: string): Promise<string>;
|
|
52
|
+
};
|
|
53
|
+
|
|
4
54
|
declare class FsFixture {
|
|
5
55
|
/**
|
|
6
56
|
* Path to the fixture directory.
|
|
7
57
|
*/
|
|
8
58
|
readonly path: string;
|
|
59
|
+
readonly fs: FsPromises;
|
|
9
60
|
/**
|
|
10
61
|
* Create a Fixture instance from a path. Does not create the fixture directory.
|
|
11
62
|
*
|
|
12
63
|
* @param fixturePath - The path to the fixture directory
|
|
64
|
+
* @param fsApi - Optional fs/promises-compatible API. Defaults to real node:fs/promises.
|
|
13
65
|
*/
|
|
14
|
-
constructor(fixturePath: string);
|
|
66
|
+
constructor(fixturePath: string, fsApi?: FsPromises);
|
|
15
67
|
/**
|
|
16
68
|
* Get the full path to a subpath in the fixture directory.
|
|
17
69
|
*
|
|
@@ -160,8 +212,8 @@ declare class PathBase {
|
|
|
160
212
|
type SymlinkType = 'file' | 'dir' | 'junction';
|
|
161
213
|
declare class Symlink extends PathBase {
|
|
162
214
|
readonly target: string;
|
|
163
|
-
readonly type?: SymlinkType
|
|
164
|
-
constructor(target: string, type?: SymlinkType
|
|
215
|
+
readonly type?: SymlinkType;
|
|
216
|
+
constructor(target: string, type?: SymlinkType, filePath?: string);
|
|
165
217
|
}
|
|
166
218
|
|
|
167
219
|
type ApiBase = {
|
|
@@ -196,6 +248,22 @@ type CreateFixtureOptions = {
|
|
|
196
248
|
* Return `true` to copy the item, `false` to ignore it.
|
|
197
249
|
*/
|
|
198
250
|
templateFilter?: FilterFunction;
|
|
251
|
+
/**
|
|
252
|
+
* Custom fs/promises-compatible API for fixture operations.
|
|
253
|
+
* Use this to create fixtures in a virtual filesystem instead of on disk.
|
|
254
|
+
*
|
|
255
|
+
* Required: readFile, writeFile, readdir (with withFileTypes),
|
|
256
|
+
* mkdir, rename, access.
|
|
257
|
+
* Optional: rm (or unlink + rmdir as fallback), symlink, cp, mkdtemp.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* import { create, MemoryProvider } from '@platformatic/vfs'
|
|
262
|
+
* const vfs = create(new MemoryProvider())
|
|
263
|
+
* const fixture = await createFixture({ 'file.txt': 'hi' }, { fs: vfs.promises })
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
fs?: FsPromises;
|
|
199
267
|
};
|
|
200
268
|
/**
|
|
201
269
|
* Create a temporary test fixture directory.
|
|
@@ -229,4 +297,4 @@ type CreateFixtureOptions = {
|
|
|
229
297
|
declare const createFixture: (source?: string | FileTree, options?: CreateFixtureOptions) => Promise<FsFixture>;
|
|
230
298
|
|
|
231
299
|
export { createFixture };
|
|
232
|
-
export type { CreateFixtureOptions, FileTree, FsFixtureType as FsFixture };
|
|
300
|
+
export type { CreateFixtureOptions, FileTree, FsFixtureType as FsFixture, FsPromises };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var F=Object.defineProperty;var o=(r,t)=>F(r,"name",{value:t,configurable:!0});import y from"node:fs/promises";import c from"node:path";import{fileURLToPath as b}from"node:url";import j from"node:fs";import v from"node:os";const w=o(async(r,t)=>{try{await r.unlink(t);return}catch(i){if(D(i))return}const e=await r.readdir(t,{withFileTypes:!0});await Promise.all(e.map(i=>{const n=c.join(t,i.name);return i.isDirectory()?w(r,n):r.unlink(n)})),await r.rmdir(t)},"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(t,e){this.path=t,this.fs=e??y}getPath(...t){return c.join(this.path,...t)}exists(t=""){return this.fs.access(this.getPath(t)).then(()=>!0,()=>!1)}rm(t=""){const e=this.getPath(t);if(this.fs.rm)return this.fs.rm(e,{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,e)}cp(t,e,i){if(!this.fs.cp)throw new Error("cp() requires the fs API to support cp()");return e?(e.endsWith("/")||e.endsWith(c.sep))&&(e+=c.basename(t)):e=c.basename(t),this.fs.cp(t,this.getPath(e),i)}mkdir(t){return this.fs.mkdir(this.getPath(t),{recursive:!0})}mv(t,e){return this.fs.rename(this.getPath(t),this.getPath(e))}readFile=o(((t,e)=>this.fs.readFile(this.getPath(t),e)),"readFile");readdir=o(((t,e)=>this.fs.readdir(this.getPath(t||""),e)),"readdir");writeFile=o(((t,e,...i)=>this.fs.writeFile(this.getPath(t),e,...i)),"writeFile");async readJson(t){const e=await this.readFile(t,"utf8");return JSON.parse(e)}writeJson(t,e,i=2){return this.writeFile(t,JSON.stringify(e,null,i))}async[Symbol.asyncDispose](){await this.rm()}}const T=j.realpathSync(v.tmpdir());class p{static{o(this,"PathBase")}path;constructor(t){this.path=t}}class d extends p{static{o(this,"Directory")}}class u extends p{static{o(this,"File")}content;constructor(t,e){super(t),this.content=e}}class h extends p{static{o(this,"Symlink")}target;type;constructor(t,e,i){super(i??""),this.target=t,this.type=e}}const g=o((r,t,e)=>{const i=[];for(const n in r){if(!Object.hasOwn(r,n))continue;const f=c.join(t,n);let a=r[n];if(typeof a=="function"){const l=Object.assign(Object.create(e),{filePath:f}),m=a(l);if(m instanceof h){const s=new h(m.target,m.type,f);i.push(s);continue}else a=m}if(typeof a=="string"||Buffer.isBuffer(a))i.push(new u(f,a));else if(a&&typeof a=="object"&&!Array.isArray(a))i.push(new d(f),...g(a,f,e));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 E=o(async(r,t)=>{const e=t?.fs??y,i=t?.tempDir?c.resolve(typeof t.tempDir=="string"?t.tempDir:b(t.tempDir)):T;t?.tempDir&&await e.mkdir(i,{recursive:!0});let n;if(e.mkdtemp?n=await e.mkdtemp(c.join(i,"fs-fixture-")):(k+=1,n=c.join(i,`fs-fixture-${process.pid}-${k}`),await e.mkdir(n,{recursive:!0})),r){if(typeof r=="string"){if(!e.cp)throw new TypeError("Template directory sources require the fs API to support cp()");await e.cp(r,n,{recursive:!0,filter:t?.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 u||s instanceof h)&&l.add(c.dirname(s.path));if(await Promise.all(Array.from(l).map(s=>e.mkdir(s,{recursive:!0}))),a.some(s=>s instanceof h)&&!e.symlink)throw new TypeError("Symlinks require the fs API to support symlink()");await Promise.all(a.map(async s=>{s instanceof h?await e.symlink(s.target,s.path,s.type):s instanceof u&&await e.writeFile(s.path,s.content)}))}}return new x(n,t?.fs)},"createFixture");export{E as createFixture};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fs-fixture",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Easily create test fixtures at a temporary file-system path",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"test",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"dist",
|
|
24
24
|
"skills"
|
|
25
25
|
],
|
|
26
|
+
"type": "module",
|
|
26
27
|
"main": "./dist/index.cjs",
|
|
27
28
|
"module": "./dist/index.mjs",
|
|
28
29
|
"types": "./dist/index.d.cts",
|
|
@@ -72,6 +72,24 @@ Path syntax — these are equivalent:
|
|
|
72
72
|
{ 'src/utils/helper.js': 'code' }
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
> [!TIP]
|
|
76
|
+
> Slash-separated keys can also group a shared prefix:
|
|
77
|
+
>
|
|
78
|
+
> ```ts
|
|
79
|
+
> await createFixture({
|
|
80
|
+
> 'file.js': 'import { a } from "my-pkg";',
|
|
81
|
+
>
|
|
82
|
+
> 'node_modules/my-pkg': {
|
|
83
|
+
> 'package.json': JSON.stringify({
|
|
84
|
+
> name: 'my-pkg',
|
|
85
|
+
> type: 'module',
|
|
86
|
+
> exports: './index.js'
|
|
87
|
+
> }),
|
|
88
|
+
> 'index.js': 'export const a = 1;'
|
|
89
|
+
> }
|
|
90
|
+
> })
|
|
91
|
+
> ```
|
|
92
|
+
|
|
75
93
|
## Patterns
|
|
76
94
|
|
|
77
95
|
### Symlinks
|