@reliverse/relifso 2.2.10 β†’ 2.3.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 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/index.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
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 });
@@ -1,16 +1,15 @@
1
- import { access, appendFile, link, lstat, mkdir, readdir, readlink, rename, rm, stat, symlink, unlink, utimes, writeFile } from "node:fs/promises";
2
- export declare const fsAccess: typeof access;
3
- export declare const fsAppendFile: typeof appendFile;
4
- export declare const fsConstants: typeof import("node:fs").constants;
5
- export declare const fsLink: typeof link;
6
- export declare const fsLStat: typeof lstat;
7
- export declare const fsMkdir: typeof mkdir;
8
- export declare const fsReaddir: typeof readdir;
9
- export declare const fsReadlink: typeof readlink;
10
- export declare const fsRename: typeof rename;
11
- export declare const fsRm: typeof rm;
12
- export declare const fsStat: typeof stat;
13
- export declare const fsSymlink: typeof symlink;
14
- export declare const fsUnlink: typeof unlink;
15
- export declare const fsUtimes: typeof utimes;
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.0",
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
- "version": "2.2.10",
6
- "private": false,
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
  }