@reliverse/relifso 2.2.10 β 2.3.1
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 +452 -452
- package/dist/copy.js +1 -8
- package/dist/dir.js +2 -11
- package/dist/internal/fs.d.ts +15 -16
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,452 +1,452 @@
|
|
|
1
|
-
# @reliverse/relifso
|
|
2
|
-
|
|
3
|
-
> Ultra-performant, Bun-first file system utilities that mirror the most commonly used `fs-extra` APIs.
|
|
4
|
-
|
|
5
|
-
A drop-in replacement for `fs-extra` optimized for Bun's native file I/O APIs (`Bun.file` and `Bun.write`). Provides 100% type safety, zero dependencies, and leverages Bun's optimized syscalls (`copy_file_range`, `sendfile`, etc.) for maximum performance.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- π **Ultra-fast** - Leverages Bun's native `Bun.file()` and `Bun.write()` APIs
|
|
10
|
-
- π¦ **Zero dependencies** - Pure Bun/Node.js implementation
|
|
11
|
-
- π **Type-safe** - Full TypeScript support with comprehensive type definitions
|
|
12
|
-
- π― **fs-extra compatible** - Drop-in replacement for the most commonly used APIs
|
|
13
|
-
- πͺ **Cross-platform** - Windows-aware symlink handling with junction support
|
|
14
|
-
- π **Well-tested** - Comprehensive benchmarks and test coverage
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
bun add @reliverse/relifso
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
|
|
24
|
-
### Default Import
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
import fs from "@reliverse/relifso";
|
|
28
|
-
|
|
29
|
-
// Read and write files
|
|
30
|
-
const content = await fs.readFile("package.json", { encoding: "utf8" });
|
|
31
|
-
await fs.writeFile("output.txt", "Hello, Bun!");
|
|
32
|
-
|
|
33
|
-
// JSON operations
|
|
34
|
-
const data = await fs.readJson<{ version: string }>("package.json");
|
|
35
|
-
await fs.writeJson("config.json", { port: 3000 });
|
|
36
|
-
|
|
37
|
-
// Directory operations
|
|
38
|
-
await fs.ensureDir("dist/assets");
|
|
39
|
-
await fs.emptyDir("temp");
|
|
40
|
-
await fs.remove("old-files");
|
|
41
|
-
|
|
42
|
-
// Copy and move
|
|
43
|
-
await fs.copy("src", "dist");
|
|
44
|
-
await fs.move("old.txt", "new.txt");
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Named Imports
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
import {
|
|
51
|
-
readFile,
|
|
52
|
-
writeFile,
|
|
53
|
-
readJson,
|
|
54
|
-
writeJson,
|
|
55
|
-
ensureDir,
|
|
56
|
-
copy,
|
|
57
|
-
remove,
|
|
58
|
-
} from "@reliverse/relifso";
|
|
59
|
-
|
|
60
|
-
await ensureDir("build");
|
|
61
|
-
await writeFile("build/index.js", "console.log('Hello');");
|
|
62
|
-
const data = await readJson("package.json");
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## API Reference
|
|
66
|
-
|
|
67
|
-
### File Operations
|
|
68
|
-
|
|
69
|
-
#### `readFile(path, options?)`
|
|
70
|
-
|
|
71
|
-
Read a file as a string with various encodings or binary (`Uint8Array`).
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
// Read as binary (default)
|
|
75
|
-
const buffer: Uint8Array = await fs.readFile("image.png");
|
|
76
|
-
|
|
77
|
-
// Read as UTF-8 string
|
|
78
|
-
const text: string = await fs.readFile("file.txt", { encoding: "utf8" });
|
|
79
|
-
|
|
80
|
-
// Supported encodings: utf8, utf-8, ascii, base64, hex, latin1, ucs-2, ucs2, utf16le, binary
|
|
81
|
-
const base64: string = await fs.readFile("file.bin", { encoding: "base64" });
|
|
82
|
-
const hex: string = await fs.readFile("file.bin", { encoding: "hex" });
|
|
83
|
-
const ascii: string = await fs.readFile("file.txt", { encoding: "ascii" });
|
|
84
|
-
const latin1: string = await fs.readFile("file.txt", { encoding: "latin1" });
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
#### `writeFile(destination, data, options?)`
|
|
88
|
-
|
|
89
|
-
Write data to a file. Accepts strings, `Uint8Array`, `Blob`, or `BunFile`.
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
// Write string (UTF-8 by default)
|
|
93
|
-
await fs.writeFile("output.txt", "Hello, World!");
|
|
94
|
-
|
|
95
|
-
// Write with specific encoding
|
|
96
|
-
await fs.writeFile("output.txt", "ΠΡΠΈΠ²ΡΡ", { encoding: "utf8" });
|
|
97
|
-
await fs.writeFile("output.txt", "Hello", { encoding: "latin1" });
|
|
98
|
-
await fs.writeFile("output.txt", "Hello", { encoding: "ascii" });
|
|
99
|
-
|
|
100
|
-
// Write binary data
|
|
101
|
-
await fs.writeFile("data.bin", new Uint8Array([1, 2, 3]));
|
|
102
|
-
|
|
103
|
-
// Write from BunFile
|
|
104
|
-
await fs.writeFile("copy.txt", Bun.file("original.txt"));
|
|
105
|
-
|
|
106
|
-
// Write with file mode
|
|
107
|
-
await fs.writeFile("script.sh", "#!/bin/bash", { mode: 0o755 });
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### `appendFile(file, data, options?)`
|
|
111
|
-
|
|
112
|
-
Append data to a file, creating it if it doesn't exist.
|
|
113
|
-
|
|
114
|
-
```ts
|
|
115
|
-
// Append string to file
|
|
116
|
-
await fs.appendFile("log.txt", "New log entry\n");
|
|
117
|
-
|
|
118
|
-
// Append with encoding
|
|
119
|
-
await fs.appendFile("log.txt", "Entry", { encoding: "utf8" });
|
|
120
|
-
|
|
121
|
-
// Append binary data
|
|
122
|
-
await fs.appendFile("data.bin", new Uint8Array([1, 2, 3]));
|
|
123
|
-
|
|
124
|
-
// Append with file mode (only applies when creating new file)
|
|
125
|
-
await fs.appendFile("log.txt", "Entry\n", { mode: 0o644 });
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
#### `readJson<T>(path)`
|
|
129
|
-
|
|
130
|
-
Read and parse a JSON file asynchronously.
|
|
131
|
-
|
|
132
|
-
```ts
|
|
133
|
-
interface PackageJson {
|
|
134
|
-
name: string;
|
|
135
|
-
version: string;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const pkg = await fs.readJson<PackageJson>("package.json");
|
|
139
|
-
console.log(pkg.name); // Type-safe access
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
#### `readJSONSync<T>(path)`
|
|
143
|
-
|
|
144
|
-
Read and parse a JSON file synchronously.
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
interface PackageJson {
|
|
148
|
-
name: string;
|
|
149
|
-
version: string;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Synchronous version - blocks until file is read
|
|
153
|
-
const pkg = fs.readJSONSync<PackageJson>("package.json");
|
|
154
|
-
console.log(pkg.name); // Type-safe access
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
#### `writeJson(destination, data, options?)`
|
|
158
|
-
|
|
159
|
-
Write data as JSON to a file.
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
await fs.writeJson("config.json", { port: 3000, host: "localhost" });
|
|
163
|
-
|
|
164
|
-
// Custom indentation
|
|
165
|
-
await fs.writeJson("config.json", data, { spaces: 4 });
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
#### `outputFile(destination, data, options?)`
|
|
169
|
-
|
|
170
|
-
Write a file, automatically creating parent directories if needed.
|
|
171
|
-
|
|
172
|
-
```ts
|
|
173
|
-
// Creates "build/assets" directory if it doesn't exist
|
|
174
|
-
await fs.outputFile("build/assets/style.css", "body { margin: 0; }");
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
#### `outputJson(destination, data, options?)`
|
|
178
|
-
|
|
179
|
-
Write JSON to a file, automatically creating parent directories.
|
|
180
|
-
|
|
181
|
-
```ts
|
|
182
|
-
await fs.outputJson("build/meta.json", { version: "1.0.0" });
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### Directory Operations
|
|
186
|
-
|
|
187
|
-
#### `ensureDir(path)`
|
|
188
|
-
|
|
189
|
-
Ensure a directory exists, creating it and any necessary parent directories.
|
|
190
|
-
|
|
191
|
-
```ts
|
|
192
|
-
await fs.ensureDir("dist/assets/images");
|
|
193
|
-
// Creates: dist/assets/images (and all parent directories)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
#### `mkdirp(path)`
|
|
197
|
-
|
|
198
|
-
Alias for `ensureDir`.
|
|
199
|
-
|
|
200
|
-
#### `ensureFile(path)`
|
|
201
|
-
|
|
202
|
-
Ensure a file exists, creating it and any necessary parent directories.
|
|
203
|
-
|
|
204
|
-
```ts
|
|
205
|
-
await fs.ensureFile("logs/app.log");
|
|
206
|
-
// Creates: logs/ directory and app.log file
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
#### `readdir(path, options?)`
|
|
210
|
-
|
|
211
|
-
Read directory contents.
|
|
212
|
-
|
|
213
|
-
```ts
|
|
214
|
-
// Get file names
|
|
215
|
-
const files = await fs.readdir("src");
|
|
216
|
-
|
|
217
|
-
// With file types
|
|
218
|
-
const entries = await fs.readdir("src", { withFileTypes: true });
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
#### `readdirRecursive(path, options?)`
|
|
222
|
-
|
|
223
|
-
Recursively read all files in a directory.
|
|
224
|
-
|
|
225
|
-
```ts
|
|
226
|
-
// Get all files recursively
|
|
227
|
-
const allFiles = await fs.readdirRecursive("src");
|
|
228
|
-
|
|
229
|
-
// Filter by extension
|
|
230
|
-
const tsFiles = await fs.readdirRecursive("src", {
|
|
231
|
-
extensions: ["ts", "tsx"],
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// Follow symlinks
|
|
235
|
-
const files = await fs.readdirRecursive("src", {
|
|
236
|
-
followSymlinks: true,
|
|
237
|
-
});
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
#### `listFiles(path, options?)`
|
|
241
|
-
|
|
242
|
-
Alias for `readdirRecursive`.
|
|
243
|
-
|
|
244
|
-
#### `emptyDir(path, options?)`
|
|
245
|
-
|
|
246
|
-
Remove all files and subdirectories from a directory.
|
|
247
|
-
|
|
248
|
-
```ts
|
|
249
|
-
await fs.emptyDir("temp");
|
|
250
|
-
|
|
251
|
-
// With filter
|
|
252
|
-
await fs.emptyDir("temp", {
|
|
253
|
-
filter: (path) => !path.includes("keep-me"),
|
|
254
|
-
});
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
#### `remove(path, options?)`
|
|
258
|
-
|
|
259
|
-
Remove a file or directory recursively.
|
|
260
|
-
|
|
261
|
-
```ts
|
|
262
|
-
// Remove file
|
|
263
|
-
await fs.remove("old-file.txt");
|
|
264
|
-
|
|
265
|
-
// Remove directory
|
|
266
|
-
await fs.remove("dist");
|
|
267
|
-
|
|
268
|
-
// Force removal (ignore errors)
|
|
269
|
-
await fs.remove("locked-dir", { force: true });
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
#### `pathExists(path)`
|
|
273
|
-
|
|
274
|
-
Check if a path exists.
|
|
275
|
-
|
|
276
|
-
```ts
|
|
277
|
-
if (await fs.pathExists("config.json")) {
|
|
278
|
-
const config = await fs.readJson("config.json");
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
#### `sizeOf(path, options?)`
|
|
283
|
-
|
|
284
|
-
Get the total size of a file or directory.
|
|
285
|
-
|
|
286
|
-
```ts
|
|
287
|
-
// File size
|
|
288
|
-
const fileSize = await fs.sizeOf("large-file.zip");
|
|
289
|
-
|
|
290
|
-
// Directory size (recursive)
|
|
291
|
-
const dirSize = await fs.sizeOf("node_modules");
|
|
292
|
-
|
|
293
|
-
// Follow symlinks
|
|
294
|
-
const size = await fs.sizeOf("symlink", { followSymlinks: true });
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Copy & Move Operations
|
|
298
|
-
|
|
299
|
-
#### `copy(source, destination, options?)`
|
|
300
|
-
|
|
301
|
-
Copy a file or directory.
|
|
302
|
-
|
|
303
|
-
```ts
|
|
304
|
-
// Copy file
|
|
305
|
-
await fs.copy("src/
|
|
306
|
-
|
|
307
|
-
// Copy directory
|
|
308
|
-
await fs.copy("src", "dist");
|
|
309
|
-
|
|
310
|
-
// With options
|
|
311
|
-
await fs.copy("src", "dist", {
|
|
312
|
-
overwrite: false, // Don't overwrite existing files
|
|
313
|
-
dereference: true, // Follow symlinks
|
|
314
|
-
filter: (path) => !path.includes("test"), // Filter files
|
|
315
|
-
});
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
#### `move(source, destination, options?)`
|
|
319
|
-
|
|
320
|
-
Move (rename) a file or directory.
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
// Move file
|
|
324
|
-
await fs.move("old.txt", "new.txt");
|
|
325
|
-
|
|
326
|
-
// Move directory
|
|
327
|
-
await fs.move("src", "lib");
|
|
328
|
-
|
|
329
|
-
// With options
|
|
330
|
-
await fs.move("old.txt", "new.txt", { overwrite: true });
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### Link Operations
|
|
334
|
-
|
|
335
|
-
#### `ensureLink(source, destination)`
|
|
336
|
-
|
|
337
|
-
Create a hard link, ensuring the destination exists.
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
await fs.ensureLink("original.txt", "link.txt");
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
#### `ensureSymlink(source, destination, options?)`
|
|
344
|
-
|
|
345
|
-
Create a symbolic link, ensuring the destination exists.
|
|
346
|
-
|
|
347
|
-
```ts
|
|
348
|
-
// Unix/Linux/Mac
|
|
349
|
-
await fs.ensureSymlink("target", "link");
|
|
350
|
-
|
|
351
|
-
// Windows (automatic junction detection)
|
|
352
|
-
await fs.ensureSymlink("target", "link", { type: "dir" });
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
### Utility Functions
|
|
356
|
-
|
|
357
|
-
#### `touch(path, options?)`
|
|
358
|
-
|
|
359
|
-
Update file access and modification times, creating the file if it doesn't exist.
|
|
360
|
-
|
|
361
|
-
```ts
|
|
362
|
-
// Update to current time
|
|
363
|
-
await fs.touch("file.txt");
|
|
364
|
-
|
|
365
|
-
// Set specific times
|
|
366
|
-
await fs.touch("file.txt", {
|
|
367
|
-
mtime: new Date("2024-01-01"),
|
|
368
|
-
atime: new Date("2024-01-01"),
|
|
369
|
-
});
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
#### `readLines(path, options?)`
|
|
373
|
-
|
|
374
|
-
Read a file and return its contents as an array of lines.
|
|
375
|
-
|
|
376
|
-
```ts
|
|
377
|
-
// Basic usage
|
|
378
|
-
const lines = await fs.readLines("file.txt");
|
|
379
|
-
|
|
380
|
-
// With options
|
|
381
|
-
const lines = await fs.readLines("file.txt", {
|
|
382
|
-
trim: true, // Trim whitespace
|
|
383
|
-
skipEmpty: true, // Skip empty lines
|
|
384
|
-
maxLines: 100, // Limit number of lines
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
## Performance
|
|
389
|
-
|
|
390
|
-
This library is optimized for Bun's native file I/O APIs:
|
|
391
|
-
|
|
392
|
-
- **`Bun.file().bytes()`** - Direct binary reading without conversion overhead
|
|
393
|
-
- **`Bun.file().json()`** - Native JSON parsing
|
|
394
|
-
- **`Bun.write()`** - Uses optimized syscalls (`copy_file_range`, `sendfile`, `clonefile`, `fcopyfile`)
|
|
395
|
-
- **`Bun.file().exists()`** - Fast existence checks
|
|
396
|
-
|
|
397
|
-
Run benchmarks:
|
|
398
|
-
|
|
399
|
-
```bash
|
|
400
|
-
bun run perf.ts
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
## Migration from fs-extra
|
|
404
|
-
|
|
405
|
-
This library is designed as a drop-in replacement for the most commonly used `fs-extra` APIs:
|
|
406
|
-
|
|
407
|
-
```ts
|
|
408
|
-
// Before (fs-extra)
|
|
409
|
-
import * as fs from "fs-extra";
|
|
410
|
-
|
|
411
|
-
// After (@reliverse/relifso)
|
|
412
|
-
import fs from "@reliverse/relifso";
|
|
413
|
-
|
|
414
|
-
// API is identical for supported methods
|
|
415
|
-
await fs.ensureDir("dist");
|
|
416
|
-
await fs.copy("src", "dist");
|
|
417
|
-
await fs.readJson("package.json");
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**Note:** This library focuses on the most commonly used `fs-extra` methods. For less common APIs, you may need to use `node:fs` directly.
|
|
421
|
-
|
|
422
|
-
## TypeScript Support
|
|
423
|
-
|
|
424
|
-
Full TypeScript support with comprehensive type definitions:
|
|
425
|
-
|
|
426
|
-
```ts
|
|
427
|
-
import type {
|
|
428
|
-
CopyOptions,
|
|
429
|
-
FileEncoding,
|
|
430
|
-
ReadFileOptions,
|
|
431
|
-
WriteFileOptions,
|
|
432
|
-
JsonWriteOptions,
|
|
433
|
-
} from "@reliverse/relifso";
|
|
434
|
-
|
|
435
|
-
const options: CopyOptions = {
|
|
436
|
-
overwrite: true,
|
|
437
|
-
filter: (path) => path.endsWith(".ts"),
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
// Type-safe encoding
|
|
441
|
-
const encoding: FileEncoding = "base64";
|
|
442
|
-
const data = await fs.readFile("file.bin", { encoding });
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
## Requirements
|
|
446
|
-
|
|
447
|
-
- **Bun** >= 1.0 (recommended for optimal performance)
|
|
448
|
-
- **Node.js** >= 18 (fallback to `node:fs` when Bun APIs aren't available)
|
|
449
|
-
|
|
450
|
-
## License
|
|
451
|
-
|
|
452
|
-
MIT
|
|
1
|
+
# @reliverse/relifso
|
|
2
|
+
|
|
3
|
+
> Ultra-performant, Bun-first file system utilities that mirror the most commonly used `fs-extra` APIs.
|
|
4
|
+
|
|
5
|
+
A drop-in replacement for `fs-extra` optimized for Bun's native file I/O APIs (`Bun.file` and `Bun.write`). Provides 100% type safety, zero dependencies, and leverages Bun's optimized syscalls (`copy_file_range`, `sendfile`, etc.) for maximum performance.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- π **Ultra-fast** - Leverages Bun's native `Bun.file()` and `Bun.write()` APIs
|
|
10
|
+
- π¦ **Zero dependencies** - Pure Bun/Node.js implementation
|
|
11
|
+
- π **Type-safe** - Full TypeScript support with comprehensive type definitions
|
|
12
|
+
- π― **fs-extra compatible** - Drop-in replacement for the most commonly used APIs
|
|
13
|
+
- πͺ **Cross-platform** - Windows-aware symlink handling with junction support
|
|
14
|
+
- π **Well-tested** - Comprehensive benchmarks and test coverage
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun add @reliverse/relifso
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Default Import
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import fs from "@reliverse/relifso";
|
|
28
|
+
|
|
29
|
+
// Read and write files
|
|
30
|
+
const content = await fs.readFile("package.json", { encoding: "utf8" });
|
|
31
|
+
await fs.writeFile("output.txt", "Hello, Bun!");
|
|
32
|
+
|
|
33
|
+
// JSON operations
|
|
34
|
+
const data = await fs.readJson<{ version: string }>("package.json");
|
|
35
|
+
await fs.writeJson("config.json", { port: 3000 });
|
|
36
|
+
|
|
37
|
+
// Directory operations
|
|
38
|
+
await fs.ensureDir("dist/assets");
|
|
39
|
+
await fs.emptyDir("temp");
|
|
40
|
+
await fs.remove("old-files");
|
|
41
|
+
|
|
42
|
+
// Copy and move
|
|
43
|
+
await fs.copy("src", "dist");
|
|
44
|
+
await fs.move("old.txt", "new.txt");
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Named Imports
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import {
|
|
51
|
+
readFile,
|
|
52
|
+
writeFile,
|
|
53
|
+
readJson,
|
|
54
|
+
writeJson,
|
|
55
|
+
ensureDir,
|
|
56
|
+
copy,
|
|
57
|
+
remove,
|
|
58
|
+
} from "@reliverse/relifso";
|
|
59
|
+
|
|
60
|
+
await ensureDir("build");
|
|
61
|
+
await writeFile("build/index.js", "console.log('Hello');");
|
|
62
|
+
const data = await readJson("package.json");
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## API Reference
|
|
66
|
+
|
|
67
|
+
### File Operations
|
|
68
|
+
|
|
69
|
+
#### `readFile(path, options?)`
|
|
70
|
+
|
|
71
|
+
Read a file as a string with various encodings or binary (`Uint8Array`).
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// Read as binary (default)
|
|
75
|
+
const buffer: Uint8Array = await fs.readFile("image.png");
|
|
76
|
+
|
|
77
|
+
// Read as UTF-8 string
|
|
78
|
+
const text: string = await fs.readFile("file.txt", { encoding: "utf8" });
|
|
79
|
+
|
|
80
|
+
// Supported encodings: utf8, utf-8, ascii, base64, hex, latin1, ucs-2, ucs2, utf16le, binary
|
|
81
|
+
const base64: string = await fs.readFile("file.bin", { encoding: "base64" });
|
|
82
|
+
const hex: string = await fs.readFile("file.bin", { encoding: "hex" });
|
|
83
|
+
const ascii: string = await fs.readFile("file.txt", { encoding: "ascii" });
|
|
84
|
+
const latin1: string = await fs.readFile("file.txt", { encoding: "latin1" });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### `writeFile(destination, data, options?)`
|
|
88
|
+
|
|
89
|
+
Write data to a file. Accepts strings, `Uint8Array`, `Blob`, or `BunFile`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
// Write string (UTF-8 by default)
|
|
93
|
+
await fs.writeFile("output.txt", "Hello, World!");
|
|
94
|
+
|
|
95
|
+
// Write with specific encoding
|
|
96
|
+
await fs.writeFile("output.txt", "ΠΡΠΈΠ²ΡΡ", { encoding: "utf8" });
|
|
97
|
+
await fs.writeFile("output.txt", "Hello", { encoding: "latin1" });
|
|
98
|
+
await fs.writeFile("output.txt", "Hello", { encoding: "ascii" });
|
|
99
|
+
|
|
100
|
+
// Write binary data
|
|
101
|
+
await fs.writeFile("data.bin", new Uint8Array([1, 2, 3]));
|
|
102
|
+
|
|
103
|
+
// Write from BunFile
|
|
104
|
+
await fs.writeFile("copy.txt", Bun.file("original.txt"));
|
|
105
|
+
|
|
106
|
+
// Write with file mode
|
|
107
|
+
await fs.writeFile("script.sh", "#!/bin/bash", { mode: 0o755 });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### `appendFile(file, data, options?)`
|
|
111
|
+
|
|
112
|
+
Append data to a file, creating it if it doesn't exist.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// Append string to file
|
|
116
|
+
await fs.appendFile("log.txt", "New log entry\n");
|
|
117
|
+
|
|
118
|
+
// Append with encoding
|
|
119
|
+
await fs.appendFile("log.txt", "Entry", { encoding: "utf8" });
|
|
120
|
+
|
|
121
|
+
// Append binary data
|
|
122
|
+
await fs.appendFile("data.bin", new Uint8Array([1, 2, 3]));
|
|
123
|
+
|
|
124
|
+
// Append with file mode (only applies when creating new file)
|
|
125
|
+
await fs.appendFile("log.txt", "Entry\n", { mode: 0o644 });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `readJson<T>(path)`
|
|
129
|
+
|
|
130
|
+
Read and parse a JSON file asynchronously.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
interface PackageJson {
|
|
134
|
+
name: string;
|
|
135
|
+
version: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const pkg = await fs.readJson<PackageJson>("package.json");
|
|
139
|
+
console.log(pkg.name); // Type-safe access
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `readJSONSync<T>(path)`
|
|
143
|
+
|
|
144
|
+
Read and parse a JSON file synchronously.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
interface PackageJson {
|
|
148
|
+
name: string;
|
|
149
|
+
version: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Synchronous version - blocks until file is read
|
|
153
|
+
const pkg = fs.readJSONSync<PackageJson>("package.json");
|
|
154
|
+
console.log(pkg.name); // Type-safe access
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `writeJson(destination, data, options?)`
|
|
158
|
+
|
|
159
|
+
Write data as JSON to a file.
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
await fs.writeJson("config.json", { port: 3000, host: "localhost" });
|
|
163
|
+
|
|
164
|
+
// Custom indentation
|
|
165
|
+
await fs.writeJson("config.json", data, { spaces: 4 });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### `outputFile(destination, data, options?)`
|
|
169
|
+
|
|
170
|
+
Write a file, automatically creating parent directories if needed.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// Creates "build/assets" directory if it doesn't exist
|
|
174
|
+
await fs.outputFile("build/assets/style.css", "body { margin: 0; }");
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### `outputJson(destination, data, options?)`
|
|
178
|
+
|
|
179
|
+
Write JSON to a file, automatically creating parent directories.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
await fs.outputJson("build/meta.json", { version: "1.0.0" });
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Directory Operations
|
|
186
|
+
|
|
187
|
+
#### `ensureDir(path)`
|
|
188
|
+
|
|
189
|
+
Ensure a directory exists, creating it and any necessary parent directories.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
await fs.ensureDir("dist/assets/images");
|
|
193
|
+
// Creates: dist/assets/images (and all parent directories)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### `mkdirp(path)`
|
|
197
|
+
|
|
198
|
+
Alias for `ensureDir`.
|
|
199
|
+
|
|
200
|
+
#### `ensureFile(path)`
|
|
201
|
+
|
|
202
|
+
Ensure a file exists, creating it and any necessary parent directories.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
await fs.ensureFile("logs/app.log");
|
|
206
|
+
// Creates: logs/ directory and app.log file
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### `readdir(path, options?)`
|
|
210
|
+
|
|
211
|
+
Read directory contents.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
// Get file names
|
|
215
|
+
const files = await fs.readdir("src");
|
|
216
|
+
|
|
217
|
+
// With file types
|
|
218
|
+
const entries = await fs.readdir("src", { withFileTypes: true });
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### `readdirRecursive(path, options?)`
|
|
222
|
+
|
|
223
|
+
Recursively read all files in a directory.
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// Get all files recursively
|
|
227
|
+
const allFiles = await fs.readdirRecursive("src");
|
|
228
|
+
|
|
229
|
+
// Filter by extension
|
|
230
|
+
const tsFiles = await fs.readdirRecursive("src", {
|
|
231
|
+
extensions: ["ts", "tsx"],
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Follow symlinks
|
|
235
|
+
const files = await fs.readdirRecursive("src", {
|
|
236
|
+
followSymlinks: true,
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### `listFiles(path, options?)`
|
|
241
|
+
|
|
242
|
+
Alias for `readdirRecursive`.
|
|
243
|
+
|
|
244
|
+
#### `emptyDir(path, options?)`
|
|
245
|
+
|
|
246
|
+
Remove all files and subdirectories from a directory.
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
await fs.emptyDir("temp");
|
|
250
|
+
|
|
251
|
+
// With filter
|
|
252
|
+
await fs.emptyDir("temp", {
|
|
253
|
+
filter: (path) => !path.includes("keep-me"),
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### `remove(path, options?)`
|
|
258
|
+
|
|
259
|
+
Remove a file or directory recursively.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// Remove file
|
|
263
|
+
await fs.remove("old-file.txt");
|
|
264
|
+
|
|
265
|
+
// Remove directory
|
|
266
|
+
await fs.remove("dist");
|
|
267
|
+
|
|
268
|
+
// Force removal (ignore errors)
|
|
269
|
+
await fs.remove("locked-dir", { force: true });
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### `pathExists(path)`
|
|
273
|
+
|
|
274
|
+
Check if a path exists.
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
if (await fs.pathExists("config.json")) {
|
|
278
|
+
const config = await fs.readJson("config.json");
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### `sizeOf(path, options?)`
|
|
283
|
+
|
|
284
|
+
Get the total size of a file or directory.
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
// File size
|
|
288
|
+
const fileSize = await fs.sizeOf("large-file.zip");
|
|
289
|
+
|
|
290
|
+
// Directory size (recursive)
|
|
291
|
+
const dirSize = await fs.sizeOf("node_modules");
|
|
292
|
+
|
|
293
|
+
// Follow symlinks
|
|
294
|
+
const size = await fs.sizeOf("symlink", { followSymlinks: true });
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Copy & Move Operations
|
|
298
|
+
|
|
299
|
+
#### `copy(source, destination, options?)`
|
|
300
|
+
|
|
301
|
+
Copy a file or directory.
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
// Copy file
|
|
305
|
+
await fs.copy("src/mod.ts", "dist/index.js");
|
|
306
|
+
|
|
307
|
+
// Copy directory
|
|
308
|
+
await fs.copy("src", "dist");
|
|
309
|
+
|
|
310
|
+
// With options
|
|
311
|
+
await fs.copy("src", "dist", {
|
|
312
|
+
overwrite: false, // Don't overwrite existing files
|
|
313
|
+
dereference: true, // Follow symlinks
|
|
314
|
+
filter: (path) => !path.includes("test"), // Filter files
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### `move(source, destination, options?)`
|
|
319
|
+
|
|
320
|
+
Move (rename) a file or directory.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
// Move file
|
|
324
|
+
await fs.move("old.txt", "new.txt");
|
|
325
|
+
|
|
326
|
+
// Move directory
|
|
327
|
+
await fs.move("src", "lib");
|
|
328
|
+
|
|
329
|
+
// With options
|
|
330
|
+
await fs.move("old.txt", "new.txt", { overwrite: true });
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Link Operations
|
|
334
|
+
|
|
335
|
+
#### `ensureLink(source, destination)`
|
|
336
|
+
|
|
337
|
+
Create a hard link, ensuring the destination exists.
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
await fs.ensureLink("original.txt", "link.txt");
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### `ensureSymlink(source, destination, options?)`
|
|
344
|
+
|
|
345
|
+
Create a symbolic link, ensuring the destination exists.
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
// Unix/Linux/Mac
|
|
349
|
+
await fs.ensureSymlink("target", "link");
|
|
350
|
+
|
|
351
|
+
// Windows (automatic junction detection)
|
|
352
|
+
await fs.ensureSymlink("target", "link", { type: "dir" });
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Utility Functions
|
|
356
|
+
|
|
357
|
+
#### `touch(path, options?)`
|
|
358
|
+
|
|
359
|
+
Update file access and modification times, creating the file if it doesn't exist.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
// Update to current time
|
|
363
|
+
await fs.touch("file.txt");
|
|
364
|
+
|
|
365
|
+
// Set specific times
|
|
366
|
+
await fs.touch("file.txt", {
|
|
367
|
+
mtime: new Date("2024-01-01"),
|
|
368
|
+
atime: new Date("2024-01-01"),
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### `readLines(path, options?)`
|
|
373
|
+
|
|
374
|
+
Read a file and return its contents as an array of lines.
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
// Basic usage
|
|
378
|
+
const lines = await fs.readLines("file.txt");
|
|
379
|
+
|
|
380
|
+
// With options
|
|
381
|
+
const lines = await fs.readLines("file.txt", {
|
|
382
|
+
trim: true, // Trim whitespace
|
|
383
|
+
skipEmpty: true, // Skip empty lines
|
|
384
|
+
maxLines: 100, // Limit number of lines
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Performance
|
|
389
|
+
|
|
390
|
+
This library is optimized for Bun's native file I/O APIs:
|
|
391
|
+
|
|
392
|
+
- **`Bun.file().bytes()`** - Direct binary reading without conversion overhead
|
|
393
|
+
- **`Bun.file().json()`** - Native JSON parsing
|
|
394
|
+
- **`Bun.write()`** - Uses optimized syscalls (`copy_file_range`, `sendfile`, `clonefile`, `fcopyfile`)
|
|
395
|
+
- **`Bun.file().exists()`** - Fast existence checks
|
|
396
|
+
|
|
397
|
+
Run benchmarks:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
bun run perf.ts
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Migration from fs-extra
|
|
404
|
+
|
|
405
|
+
This library is designed as a drop-in replacement for the most commonly used `fs-extra` APIs:
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
// Before (fs-extra)
|
|
409
|
+
import * as fs from "fs-extra";
|
|
410
|
+
|
|
411
|
+
// After (@reliverse/relifso)
|
|
412
|
+
import fs from "@reliverse/relifso";
|
|
413
|
+
|
|
414
|
+
// API is identical for supported methods
|
|
415
|
+
await fs.ensureDir("dist");
|
|
416
|
+
await fs.copy("src", "dist");
|
|
417
|
+
await fs.readJson("package.json");
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Note:** This library focuses on the most commonly used `fs-extra` methods. For less common APIs, you may need to use `node:fs` directly.
|
|
421
|
+
|
|
422
|
+
## TypeScript Support
|
|
423
|
+
|
|
424
|
+
Full TypeScript support with comprehensive type definitions:
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
import type {
|
|
428
|
+
CopyOptions,
|
|
429
|
+
FileEncoding,
|
|
430
|
+
ReadFileOptions,
|
|
431
|
+
WriteFileOptions,
|
|
432
|
+
JsonWriteOptions,
|
|
433
|
+
} from "@reliverse/relifso";
|
|
434
|
+
|
|
435
|
+
const options: CopyOptions = {
|
|
436
|
+
overwrite: true,
|
|
437
|
+
filter: (path) => path.endsWith(".ts"),
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// Type-safe encoding
|
|
441
|
+
const encoding: FileEncoding = "base64";
|
|
442
|
+
const data = await fs.readFile("file.bin", { encoding });
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Requirements
|
|
446
|
+
|
|
447
|
+
- **Bun** >= 1.0 (recommended for optimal performance)
|
|
448
|
+
- **Node.js** >= 18 (fallback to `node:fs` when Bun APIs aren't available)
|
|
449
|
+
|
|
450
|
+
## License
|
|
451
|
+
|
|
452
|
+
MIT
|
package/dist/copy.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import { ensureDir, pathExists, remove } from "./dir.js";
|
|
3
|
-
import {
|
|
4
|
-
fsLStat,
|
|
5
|
-
fsReaddir,
|
|
6
|
-
fsReadlink,
|
|
7
|
-
fsRename,
|
|
8
|
-
fsStat,
|
|
9
|
-
fsSymlink
|
|
10
|
-
} from "./internal/fs.js";
|
|
3
|
+
import { fsLStat, fsReaddir, fsReadlink, fsRename, fsStat, fsSymlink } from "./internal/fs.js";
|
|
11
4
|
import { toPathString } from "./internal/path.js";
|
|
12
5
|
const shouldCopyEntry = async (path, filter) => {
|
|
13
6
|
if (!filter) {
|
package/dist/dir.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
fsLStat,
|
|
4
|
-
fsMkdir,
|
|
5
|
-
fsReaddir,
|
|
6
|
-
fsRm,
|
|
7
|
-
fsStat,
|
|
8
|
-
fsUnlink
|
|
9
|
-
} from "./internal/fs.js";
|
|
2
|
+
import { fsLStat, fsMkdir, fsReaddir, fsRm, fsStat, fsUnlink } from "./internal/fs.js";
|
|
10
3
|
import { toPathString } from "./internal/path.js";
|
|
11
4
|
export const pathExists = async (path) => {
|
|
12
5
|
const pathStr = toPathString(path);
|
|
@@ -69,9 +62,7 @@ export const readdirRecursive = async (path, options) => {
|
|
|
69
62
|
const queue = [target];
|
|
70
63
|
const files = [];
|
|
71
64
|
const follow = options?.followSymlinks ?? false;
|
|
72
|
-
const extensions = options?.extensions?.map(
|
|
73
|
-
(ext) => ext.startsWith(".") ? ext : `.${ext}`
|
|
74
|
-
);
|
|
65
|
+
const extensions = options?.extensions?.map((ext) => ext.startsWith(".") ? ext : `.${ext}`);
|
|
75
66
|
while (queue.length > 0) {
|
|
76
67
|
const current = queue.pop();
|
|
77
68
|
const entries = await fsReaddir(current, { withFileTypes: true });
|
package/dist/internal/fs.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
12
|
-
export declare const
|
|
13
|
-
export declare const
|
|
14
|
-
export declare const
|
|
15
|
-
export declare const
|
|
16
|
-
export declare const fsWriteFile: typeof writeFile;
|
|
1
|
+
export declare const fsAccess: any;
|
|
2
|
+
export declare const fsAppendFile: any;
|
|
3
|
+
export declare const fsConstants: any;
|
|
4
|
+
export declare const fsLink: any;
|
|
5
|
+
export declare const fsLStat: any;
|
|
6
|
+
export declare const fsMkdir: any;
|
|
7
|
+
export declare const fsReaddir: any;
|
|
8
|
+
export declare const fsReadlink: any;
|
|
9
|
+
export declare const fsRename: any;
|
|
10
|
+
export declare const fsRm: any;
|
|
11
|
+
export declare const fsStat: any;
|
|
12
|
+
export declare const fsSymlink: any;
|
|
13
|
+
export declare const fsUnlink: any;
|
|
14
|
+
export declare const fsUtimes: any;
|
|
15
|
+
export declare const fsWriteFile: any;
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reliverse/relifso",
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"private": false,
|
|
3
5
|
"description": "Bun-first fs-extra style helpers (copy, ensure*, output*) for Reliverse ecosystem",
|
|
6
|
+
"license": "MIT",
|
|
4
7
|
"author": "reliverse",
|
|
5
|
-
"
|
|
6
|
-
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"package.json"
|
|
11
|
+
],
|
|
7
12
|
"type": "module",
|
|
8
13
|
"exports": {
|
|
9
14
|
".": {
|
|
@@ -13,10 +18,5 @@
|
|
|
13
18
|
},
|
|
14
19
|
"publishConfig": {
|
|
15
20
|
"access": "public"
|
|
16
|
-
}
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"package.json"
|
|
20
|
-
],
|
|
21
|
-
"license": "MIT"
|
|
21
|
+
}
|
|
22
22
|
}
|