@reliverse/relifso 1.4.4 → 2.2.7

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.
Files changed (92) hide show
  1. package/README.md +371 -367
  2. package/dist/copy.d.ts +3 -0
  3. package/dist/copy.js +95 -0
  4. package/dist/dir.d.ts +13 -0
  5. package/dist/dir.js +113 -0
  6. package/dist/file.d.ts +12 -0
  7. package/dist/file.js +169 -0
  8. package/dist/helpers.d.ts +3 -0
  9. package/dist/helpers.js +38 -0
  10. package/dist/internal/fs.d.ts +16 -0
  11. package/dist/internal/fs.js +32 -0
  12. package/dist/internal/path.d.ts +3 -0
  13. package/dist/internal/path.js +11 -0
  14. package/dist/links.d.ts +3 -0
  15. package/dist/links.js +74 -0
  16. package/dist/mod.d.ts +40 -0
  17. package/dist/mod.js +77 -0
  18. package/dist/types.d.ts +50 -0
  19. package/dist/types.js +0 -0
  20. package/package.json +15 -42
  21. package/LICENSE +0 -21
  22. package/LICENSES +0 -16
  23. package/bin/impl/bun.d.ts +0 -11
  24. package/bin/impl/bun.js +0 -23
  25. package/bin/impl/copy.d.ts +0 -40
  26. package/bin/impl/copy.js +0 -229
  27. package/bin/impl/create.d.ts +0 -34
  28. package/bin/impl/create.js +0 -54
  29. package/bin/impl/dive.d.ts +0 -27
  30. package/bin/impl/dive.js +0 -145
  31. package/bin/impl/empty.d.ts +0 -28
  32. package/bin/impl/empty.js +0 -75
  33. package/bin/impl/extras.d.ts +0 -35
  34. package/bin/impl/extras.js +0 -112
  35. package/bin/impl/json-utils.d.ts +0 -30
  36. package/bin/impl/json-utils.js +0 -46
  37. package/bin/impl/mkdirs.d.ts +0 -7
  38. package/bin/impl/mkdirs.js +0 -28
  39. package/bin/impl/move.d.ts +0 -28
  40. package/bin/impl/move.js +0 -140
  41. package/bin/impl/output-file.d.ts +0 -17
  42. package/bin/impl/output-file.js +0 -15
  43. package/bin/impl/output-json.d.ts +0 -21
  44. package/bin/impl/output-json.js +0 -77
  45. package/bin/impl/path-exists.d.ts +0 -2
  46. package/bin/impl/path-exists.js +0 -16
  47. package/bin/impl/read-file.d.ts +0 -31
  48. package/bin/impl/read-file.js +0 -165
  49. package/bin/impl/read-json.d.ts +0 -31
  50. package/bin/impl/read-json.js +0 -241
  51. package/bin/impl/remove.d.ts +0 -2
  52. package/bin/impl/remove.js +0 -8
  53. package/bin/impl/stats.d.ts +0 -31
  54. package/bin/impl/stats.js +0 -141
  55. package/bin/impl/write-file.d.ts +0 -31
  56. package/bin/impl/write-file.js +0 -177
  57. package/bin/impl/write-json.d.ts +0 -41
  58. package/bin/impl/write-json.js +0 -135
  59. package/bin/mod.d.ts +0 -253
  60. package/bin/mod.js +0 -514
  61. package/bin/utils/json/helpers/JSONRepairError.d.ts +0 -4
  62. package/bin/utils/json/helpers/JSONRepairError.js +0 -7
  63. package/bin/utils/json/helpers/JsonSchemaError.d.ts +0 -6
  64. package/bin/utils/json/helpers/JsonSchemaError.js +0 -6
  65. package/bin/utils/json/helpers/stringUtils.d.ts +0 -64
  66. package/bin/utils/json/helpers/stringUtils.js +0 -87
  67. package/bin/utils/json/regular/jsonc.d.ts +0 -45
  68. package/bin/utils/json/regular/jsonc.js +0 -88
  69. package/bin/utils/json/regular/jsonrepair.d.ts +0 -17
  70. package/bin/utils/json/regular/jsonrepair.js +0 -576
  71. package/bin/utils/json/regular/validate.d.ts +0 -22
  72. package/bin/utils/json/regular/validate.js +0 -52
  73. package/bin/utils/json/stream/JsonStreamError.d.ts +0 -6
  74. package/bin/utils/json/stream/JsonStreamError.js +0 -6
  75. package/bin/utils/json/stream/buffer/InputBuffer.d.ts +0 -13
  76. package/bin/utils/json/stream/buffer/InputBuffer.js +0 -68
  77. package/bin/utils/json/stream/buffer/OutputBuffer.d.ts +0 -17
  78. package/bin/utils/json/stream/buffer/OutputBuffer.js +0 -101
  79. package/bin/utils/json/stream/core.d.ts +0 -10
  80. package/bin/utils/json/stream/core.js +0 -695
  81. package/bin/utils/json/stream/jsonl.d.ts +0 -21
  82. package/bin/utils/json/stream/jsonl.js +0 -55
  83. package/bin/utils/json/stream/parser.d.ts +0 -14
  84. package/bin/utils/json/stream/parser.js +0 -81
  85. package/bin/utils/json/stream/stack.d.ts +0 -19
  86. package/bin/utils/json/stream/stack.js +0 -43
  87. package/bin/utils/json/stream/stream.d.ts +0 -6
  88. package/bin/utils/json/stream/stream.js +0 -30
  89. package/bin/utils/json/stream/writer.d.ts +0 -14
  90. package/bin/utils/json/stream/writer.js +0 -44
  91. package/bin/utils/log.d.ts +0 -1
  92. package/bin/utils/log.js +0 -7
package/README.md CHANGED
@@ -1,448 +1,452 @@
1
- # Relifso • Bun & Node.js Filesystem Toolkit Library
1
+ # @reliverse/relifso
2
2
 
3
- [sponsor](https://github.com/sponsors/blefnk) [discord](https://discord.gg/Pb8uKbwpsJ) [npm](https://npmjs.com/package/@reliverse/relifso) [github](https://github.com/reliverse/relifso)
3
+ > Ultra-performant, Bun-first file system utilities that mirror the most commonly used `fs-extra` APIs.
4
4
 
5
- > @reliverse/relifso is a modern node and bun filesystem toolkit. drop-in replacement for `node:fs` and `fs-extra` powered by native promises, built with es modules, and packed with dx-focused and bun-aware utilities.
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
6
 
7
7
  ## Features
8
8
 
9
- - 🔥 Both Node.js and Bun-specific filesystem features are exposed via `fs.*`
10
- - 🪄 Everything you love from `fs-extra` now simpler, cleaner, and more beginner-friendly
11
- - ⚙️ Drop-in replacement for `node:fs` with native `Promise`, `async/await`, and sync variants
12
- - 🤝 Forget about `try-catch` for common errors like "file not found" — relifso does it under the hood
13
- - 🧯 Gracefully handles errors like `EMFILE` (reading or writing a lot of files at once) and other edge cases
14
- - 📚 Consistent error-first behavior even for legacy APIs like `fs.exists()`
15
- - 📦 First-class ESM and full TypeScript support — no config hacks required
16
- - 🧼 Zero bloat — small size, zero deps, modern code, no monkey-patching
17
- - 🎯 Supports all Node.js v16+ features — optimized for Node.js v22+
18
- - 🧪 Soon: Ready for upcoming Node.js v22+ experimental features
19
- - ✌️ Bun v1.2+ ready — ships with Bun-aware enhancements out of the box
20
- - 🐦‍🔥 Finally! Your `fs.*` usage is now can correctly read/write JSON/JSONC!
21
-
22
- ## Install
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
23
17
 
24
18
  ```bash
25
- # bun • pnpm • yarn • npm
26
19
  bun add @reliverse/relifso
27
20
  ```
28
21
 
29
- **Migrate**:
22
+ ## Quick Start
30
23
 
31
- ```bash
32
- bun rm fs-extra
33
- bun rm @types/fs-extra
34
- # soon:
35
- # bun add -D @reliverse/dler
36
- # bun dler migrate fs-relifso
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");
37
45
  ```
38
46
 
39
- **Pro Tip**: _Use Ctrl+Shift+H to replace `fs-extra` with `@reliverse/relifso` in your project._
47
+ ### Named Imports
40
48
 
41
- ### Core Features
49
+ ```ts
50
+ import {
51
+ readFile,
52
+ writeFile,
53
+ readJson,
54
+ writeJson,
55
+ ensureDir,
56
+ copy,
57
+ remove,
58
+ } from "@reliverse/relifso";
42
59
 
43
- - **File Operations**
44
- - Read/write files with various encodings
45
- - Copy/move files and directories
46
- - Create/remove files and directories
47
- - File existence checks
48
- - File stats and metadata access
60
+ await ensureDir("build");
61
+ await writeFile("build/index.js", "console.log('Hello');");
62
+ const data = await readJson("package.json");
63
+ ```
49
64
 
50
- - **Directory Operations**
51
- - Create nested directories
52
- - Empty directories
53
- - Directory traversal with `dive`
54
- - Directory existence checks
65
+ ## API Reference
55
66
 
56
- - **JSON Operations**
57
- - Read/write JSON files with validation
58
- - JSON repair and validation utilities
59
- - JSON streaming support
60
- - JSONC (JSON with Comments) support
67
+ ### File Operations
61
68
 
62
- - **Bun Optimizations**
63
- - Automatic runtime detection
64
- - Optimized file operations using Bun APIs
65
- - Fast file stats and metadata access
66
- - Graceful fallbacks to Node.js APIs
69
+ #### `readFile(path, options?)`
67
70
 
68
- - **Utility Functions**
69
- - File type detection
70
- - Hidden file attribute handling
71
- - Directory emptiness checks
72
- - File size and last modified time access
71
+ Read a file as a string with various encodings or binary (`Uint8Array`).
73
72
 
74
- ### Error Handling
73
+ ```ts
74
+ // Read as binary (default)
75
+ const buffer: Uint8Array = await fs.readFile("image.png");
75
76
 
76
- - Graceful handling of common filesystem errors
77
- - Consistent error types and messages
78
- - Automatic error recovery where possible
79
- - Detailed error information for debugging
80
- - Runtime detection errors
81
- - File operation failures
82
- - All Bun-specific operations include proper error handling
83
- - Automatic fallback from Bun to Node.js APIs when needed
77
+ // Read as UTF-8 string
78
+ const text: string = await fs.readFile("file.txt", { encoding: "utf8" });
84
79
 
85
- ## Usage
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
86
 
87
- Check [./e-relifso.ts](./e-relifso.ts) and [./e-pathkit.ts](./e-pathkit.ts) for a full examples. You can clone this repo and run via `bun dev`.
87
+ #### `writeFile(destination, data, options?)`
88
88
 
89
- Relifso works just like `fs-extra` every method is promise-first, ergonomic, and future-ready.
89
+ Write data to a file. Accepts strings, `Uint8Array`, `Blob`, or `BunFile`.
90
90
 
91
91
  ```ts
92
- import { copy, pathExists, remove } from "@reliverse/relifso";
92
+ // Write string (UTF-8 by default)
93
+ await fs.writeFile("output.txt", "Hello, World!");
93
94
 
94
- await copy("src/index.ts", "dist/index.ts");
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" });
95
99
 
96
- if (await pathExists("dist/index.ts")) {
97
- await remove("dist/index.ts");
98
- }
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 });
99
108
  ```
100
109
 
101
- - ✨ Everything's bundled — modern, async, and type-safe.
102
- - 🧼 No more boilerplate like `promisify(fs.removeSync)` or using `mkdirp`, `ncp`, or `rimraf`.
103
- - 🌱 No more weird `try/catch` for common errors like "file not found."
104
- - ✌️ Just clean, predictable APIs built for 2025 and beyond.
110
+ #### `appendFile(file, data, options?)`
105
111
 
106
- ## Example
112
+ Append data to a file, creating it if it doesn't exist.
107
113
 
108
114
  ```ts
109
- import {
110
- ensureDir,
111
- outputJson,
112
- readJson,
113
- remove,
114
- } from "@reliverse/relifso";
115
+ // Append string to file
116
+ await fs.appendFile("log.txt", "New log entry\n");
115
117
 
116
- const path = "./.reliverse/config.json";
118
+ // Append with encoding
119
+ await fs.appendFile("log.txt", "Entry", { encoding: "utf8" });
117
120
 
118
- await ensureDir(".reliverse");
119
- await outputJson(path, { hello: "world" });
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
+ ```
120
127
 
121
- const config = await readJson(path);
122
- console.log(config); // { hello: 'world' }
128
+ #### `readJson<T>(path)`
123
129
 
124
- await remove(".reliverse");
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
125
140
  ```
126
141
 
127
- ## Run Example
142
+ #### `readJSONSync<T>(path)`
128
143
 
129
- Install this repository locally and run the example by using `bun dev`:
144
+ Read and parse a JSON file synchronously.
130
145
 
131
- ```bash
132
- $ bun e-mod.ts
133
- ✓ Running examples with Bun...
134
- Created directory ./tests-runtime
135
- [env] writeJson was successfully executed in Bun (for JSON)
136
- Wrote JSON tests-runtime\config.json
137
- [env] readJson was successfully executed in Bun
138
- Read JSON {"hello":"world","ts":"2025-06-02T19:01:53.291Z"}
139
- [env] copy was successfully executed in Bun
140
- Moved → Copied (with overwrite) tests-runtime\config.old.json → tests-runtime\config.copy.json
141
- [env] readFile was successfully executed in Bun
142
- Wrote & read text file Hello Relifso!
143
- [env] writeFile was successfully executed in Bun
144
- [env] writeFile was successfully executed in Bun
145
- Ensured nested & output files
146
- [env] writeJson was successfully executed in Bun (for JSON)
147
- [env] readJson was successfully executed in Bun
148
- writeJson / readJson round-trip {"foo":"bar"}
149
- [env] writeJson was successfully executed in Bun (for JSONC)
150
- Wrote JSONC tests-runtime\config.jsonc
151
- [env] readJson was successfully executed in Bun
152
- Read JSONC {
153
- "name": "relifso",
154
- "version": "1.0.0",
155
- "features": [
156
- "file operations",
157
- "directory operations",
158
- "JSONC support"
159
- ],
160
- "settings": {
161
- "debug": true,
162
- "verbose": false
163
- }
146
+ ```ts
147
+ interface PackageJson {
148
+ name: string;
149
+ version: string;
164
150
  }
165
- Emptied directory tests-runtime\empty-me
166
- [env] writeFileSync was successfully executed in Bun
167
- [env] writeJsonSync was successfully executed in Bun (for JSON)
168
- Sync JSON round-trip {"sync":true}
169
- [env] copySync was successfully executed in Bun
170
- copySync → moveSync → removeSync chain complete
171
- Directory structure via dive
172
- • tests-runtime\config-sync.json
173
- tests-runtime\config.copy.json
174
- • tests-runtime\config.jsonc
175
- • tests-runtime\config.old.json
176
- • tests-runtime\config2.json
177
- • tests-runtime\hello.txt
178
- tests-runtime\nested\deep\file.txt
179
- tests-runtime\output-file.txt
180
- Directory structure via diveSync
181
- • tests-runtime\config-sync.json
182
- tests-runtime\config.copy.json
183
- • tests-runtime\config.jsonc
184
- tests-runtime\config.old.json
185
- • tests-runtime\config2.json
186
- • tests-runtime\hello.txt
187
- tests-runtime\nested\deep\file.txt
188
- tests-runtime\output-file.txt
189
- Removed directory ./tests-runtime
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; }");
190
175
  ```
191
176
 
192
- ## Sync vs Async vs Legacy
177
+ #### `outputJson(destination, data, options?)`
193
178
 
194
- You choose your flavor:
179
+ Write JSON to a file, automatically creating parent directories.
195
180
 
196
181
  ```ts
197
- // Async/Await
198
- await copy("a.txt", "b.txt");
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)`
199
197
 
200
- // Sync
201
- copySync("a.txt", "b.txt");
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
+ });
202
233
 
203
- // Callback (legacy-style)
204
- copy("a.txt", "b.txt", err => {
205
- if (err) console.error(err);
234
+ // Follow symlinks
235
+ const files = await fs.readdirRecursive("src", {
236
+ followSymlinks: true,
206
237
  });
207
238
  ```
208
239
 
209
- All async methods return a `Promise` if no callback is passed.
210
-
211
- ## Fully Typed, Fully Modern
212
-
213
- - Written in modern ESM
214
- - Minimal dependencies
215
- - Full TypeScript declarations
216
- - Compatible with Node.js 16+, best with 22+
217
- - Async methods are built from the sync versions — no wrappers, no bloat
218
-
219
- ## What's Inside?
220
-
221
- - All async methods follow the `Promise` pattern by default.
222
- - All sync methods are safe and throw errors when needed.
223
-
224
- ### Async (recommended)
225
-
226
- #### Common Async Methods
227
-
228
- - [access](https://uwx-node-modules.github.io/fsxt/functions/access.html)
229
- - [appendFile](https://uwx-node-modules.github.io/fsxt/functions/appendFile.html)
230
- - [copy](https://uwx-node-modules.github.io/fsxt/functions/copy.html)
231
- - [copyFile](https://uwx-node-modules.github.io/fsxt/functions/copyFile.html)
232
- - [cp](https://uwx-node-modules.github.io/fsxt/functions/cp.html)
233
- - [createReadStream](https://uwx-node-modules.github.io/fsxt/functions/createReadStream.html)
234
- - [createWriteStream](https://uwx-node-modules.github.io/fsxt/functions/createWriteStream.html)
235
- - [ensureFile](https://uwx-node-modules.github.io/fsxt/functions/ensureFile.html)
236
- - [exists](https://uwx-node-modules.github.io/fsxt/functions/exists.html)
237
- - [mkdir](https://uwx-node-modules.github.io/fsxt/functions/mkdir.html)
238
- - [mkdirs](https://uwx-node-modules.github.io/fsxt/functions/mkdirs.html)
239
- - [move](https://uwx-node-modules.github.io/fsxt/functions/move.html)
240
- - [open](https://uwx-node-modules.github.io/fsxt/functions/open.html)
241
- - [outputFile](https://uwx-node-modules.github.io/fsxt/functions/outputFile.html)
242
- - [outputJson](https://uwx-node-modules.github.io/fsxt/functions/outputJson.html)
243
- - [read](https://uwx-node-modules.github.io/fsxt/functions/read.html)
244
- - [readdir](https://uwx-node-modules.github.io/fsxt/functions/readdir.html)
245
- - [readFile](https://uwx-node-modules.github.io/fsxt/functions/readFile.html)
246
- - [readJson](https://uwx-node-modules.github.io/fsxt/functions/readJson.html)
247
- - [readLines](https://uwx-node-modules.github.io/fsxt/functions/readLines.html)
248
- - [readText](https://uwx-node-modules.github.io/fsxt/functions/readText.html)
249
- - [rename](https://uwx-node-modules.github.io/fsxt/functions/rename.html)
250
- - [rm](https://uwx-node-modules.github.io/fsxt/functions/rm.html)
251
- - [rmdir](https://uwx-node-modules.github.io/fsxt/functions/rmdir.html)
252
- - [stat](https://uwx-node-modules.github.io/fsxt/functions/stat.html)
253
- - [symlink](https://uwx-node-modules.github.io/fsxt/functions/symlink.html)
254
- - [truncate](https://uwx-node-modules.github.io/fsxt/functions/truncate.html)
255
- - [unlink](https://uwx-node-modules.github.io/fsxt/functions/unlink.html)
256
- - [watch](https://uwx-node-modules.github.io/fsxt/functions/watch.html)
257
- - [watchFile](https://uwx-node-modules.github.io/fsxt/functions/watchFile.html)
258
- - [write](https://uwx-node-modules.github.io/fsxt/functions/write.html)
259
- - [writeFile](https://uwx-node-modules.github.io/fsxt/functions/writeFile.html)
260
- - [writeJson](https://uwx-node-modules.github.io/fsxt/functions/writeJson.html)
261
-
262
- #### Less Commonly Used Async Methods
263
-
264
- - [chmod](https://uwx-node-modules.github.io/fsxt/functions/chmod.html)
265
- - [chown](https://uwx-node-modules.github.io/fsxt/functions/chown.html)
266
- - [close](https://uwx-node-modules.github.io/fsxt/functions/close.html)
267
- - [dive](https://uwx-node-modules.github.io/fsxt/functions/dive.html)
268
- - [emptyDir](https://uwx-node-modules.github.io/fsxt/functions/emptyDir.html)
269
- - [ensureLink](https://uwx-node-modules.github.io/fsxt/functions/ensureLink.html)
270
- - [ensureSymlink](https://uwx-node-modules.github.io/fsxt/functions/ensureSymlink.html)
271
- - [fchmod](https://uwx-node-modules.github.io/fsxt/functions/fchmod.html)
272
- - [fchown](https://uwx-node-modules.github.io/fsxt/functions/fchown.html)
273
- - [forEachChild](https://uwx-node-modules.github.io/fsxt/functions/forEachChild.html)
274
- - [fstat](https://uwx-node-modules.github.io/fsxt/functions/fstat.html)
275
- - [ftruncate](https://uwx-node-modules.github.io/fsxt/functions/ftruncate.html)
276
- - [futimes](https://uwx-node-modules.github.io/fsxt/functions/futimes.html)
277
- - [gracefulify](https://uwx-node-modules.github.io/fsxt/functions/gracefulify.html)
278
- - [isDirectory](https://uwx-node-modules.github.io/fsxt/functions/isDirectory.html)
279
- - [isSymlink](https://uwx-node-modules.github.io/fsxt/functions/isSymlink.html)
280
- - [~~lchmod~~](https://uwx-node-modules.github.io/fsxt/functions/lchmod.html)
281
- - [lchown](https://uwx-node-modules.github.io/fsxt/functions/lchown.html)
282
- - [`link`](https://uwx-node-modules.github.io/fsxt/functions/link.html)
283
- - [lstat](https://uwx-node-modules.github.io/fsxt/functions/lstat.html)
284
- - [lutimes](https://uwx-node-modules.github.io/fsxt/functions/lutimes.html)
285
- - [mapChildren](https://uwx-node-modules.github.io/fsxt/functions/mapChildren.html)
286
- - [mapStructure](https://uwx-node-modules.github.io/fsxt/functions/mapStructure.html)
287
- - [mapStructureOrdered](https://uwx-node-modules.github.io/fsxt/functions/mapStructureOrdered.html)
288
- - [mkdtemp](https://uwx-node-modules.github.io/fsxt/functions/mkdtemp.html)
289
- - [openAsBlob](https://uwx-node-modules.github.io/fsxt/functions/openAsBlob.html)
290
- - [opendir](https://uwx-node-modules.github.io/fsxt/functions/opendir.html)
291
- - [readv](https://uwx-node-modules.github.io/fsxt/functions/readv.html)
292
- - [realpath](https://uwx-node-modules.github.io/fsxt/functions/realpath.html)
293
- - [remove](https://uwx-node-modules.github.io/fsxt/functions/remove.html)
294
- - [resolve](https://uwx-node-modules.github.io/fsxt/functions/resolve.html)
295
- - [statfs](https://uwx-node-modules.github.io/fsxt/functions/statfs.html)
296
- - [unwatchFile](https://uwx-node-modules.github.io/fsxt/functions/unwatchFile.html)
297
- - [utimes](https://uwx-node-modules.github.io/fsxt/functions/utimes.html)
298
- - [vacuum](https://uwx-node-modules.github.io/fsxt/functions/vacuum.html)
299
- - [writev](https://uwx-node-modules.github.io/fsxt/functions/writev.html)
300
-
301
- ### Sync
302
-
303
- #### Common Sync Methods
304
-
305
- - [accessSync](https://uwx-node-modules.github.io/fsxt/functions/accessSync.html)
306
- - [appendFileSync](https://uwx-node-modules.github.io/fsxt/functions/appendFileSync.html)
307
- - [copyFileSync](https://uwx-node-modules.github.io/fsxt/functions/copyFileSync.html)
308
- - [copySync](https://uwx-node-modules.github.io/fsxt/functions/copySync.html)
309
- - [cpSync](https://uwx-node-modules.github.io/fsxt/functions/cpSync.html)
310
- - [existsSync](https://uwx-node-modules.github.io/fsxt/functions/existsSync.html)
311
- - [mkdirSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirSync.html)
312
- - [mkdirsSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirsSync.html)
313
- - [moveSync](https://uwx-node-modules.github.io/fsxt/functions/moveSync.html)
314
- - [openSync](https://uwx-node-modules.github.io/fsxt/functions/openSync.html)
315
- - [outputFileSync](https://uwx-node-modules.github.io/fsxt/functions/outputFileSync.html)
316
- - [outputJsonSync](https://uwx-node-modules.github.io/fsxt/functions/outputJsonSync.html)
317
- - [readdirSync](https://uwx-node-modules.github.io/fsxt/functions/readdirSync.html)
318
- - [readFileSync](https://uwx-node-modules.github.io/fsxt/functions/readFileSync.html)
319
- - [readJsonSync](https://uwx-node-modules.github.io/fsxt/functions/readJsonSync.html)
320
- - [readTextSync](https://uwx-node-modules.github.io/fsxt/functions/readTextSync.html)
321
- - [renameSync](https://uwx-node-modules.github.io/fsxt/functions/renameSync.html)
322
- - [rmSync](https://uwx-node-modules.github.io/fsxt/functions/rmSync.html)
323
- - [rmdirSync](https://uwx-node-modules.github.io/fsxt/functions/rmdirSync.html)
324
- - [statSync](https://uwx-node-modules.github.io/fsxt/functions/statSync.html)
325
- - [symlinkSync](https://uwx-node-modules.github.io/fsxt/functions/symlinkSync.html)
326
- - [truncateSync](https://uwx-node-modules.github.io/fsxt/functions/truncateSync.html)
327
- - [unlinkSync](https://uwx-node-modules.github.io/fsxt/functions/unlinkSync.html)
328
- - [writeFileSync](https://uwx-node-modules.github.io/fsxt/functions/writeFileSync.html)
329
- - [writeJsonSync](https://uwx-node-modules.github.io/fsxt/functions/writeJsonSync.html)
330
- - [writeSync](https://uwx-node-modules.github.io/fsxt/functions/writeSync.html)
331
-
332
- #### Less Commonly Used Sync Methods
333
-
334
- - [chmodSync](https://uwx-node-modules.github.io/fsxt/functions/chmodSync.html)
335
- - [chownSync](https://uwx-node-modules.github.io/fsxt/functions/chownSync.html)
336
- - [closeSync](https://uwx-node-modules.github.io/fsxt/functions/closeSync.html)
337
- - [diveSync](https://uwx-node-modules.github.io/fsxt/functions/diveSync.html)
338
- - [emptyDirSync](https://uwx-node-modules.github.io/fsxt/functions/emptyDirSync.html)
339
- - [ensureFileSync](https://uwx-node-modules.github.io/fsxt/functions/ensureFileSync.html)
340
- - [ensureLinkSync](https://uwx-node-modules.github.io/fsxt/functions/ensureLinkSync.html)
341
- - [ensureSymlinkSync](https://uwx-node-modules.github.io/fsxt/functions/ensureSymlinkSync.html)
342
- - [fchmodSync](https://uwx-node-modules.github.io/fsxt/functions/fchmodSync.html)
343
- - [fchownSync](https://uwx-node-modules.github.io/fsxt/functions/fchownSync.html)
344
- - [fdatasync](https://uwx-node-modules.github.io/fsxt/functions/fdatasync.html)
345
- - [fdatasyncSync](https://uwx-node-modules.github.io/fsxt/functions/fdatasyncSync.html)
346
- - [forEachChildSync](https://uwx-node-modules.github.io/fsxt/functions/forEachChildSync.html)
347
- - [fstatSync](https://uwx-node-modules.github.io/fsxt/functions/fstatSync.html)
348
- - [fsync](https://uwx-node-modules.github.io/fsxt/functions/fsync.html)
349
- - [fsyncSync](https://uwx-node-modules.github.io/fsxt/functions/fsyncSync.html)
350
- - [ftruncateSync](https://uwx-node-modules.github.io/fsxt/functions/ftruncateSync.html)
351
- - [futimesSync](https://uwx-node-modules.github.io/fsxt/functions/futimesSync.html)
352
- - [isDirectorySync](https://uwx-node-modules.github.io/fsxt/functions/isDirectorySync.html)
353
- - [~~lchmodSync~~](https://uwx-node-modules.github.io/fsxt/functions/lchmodSync.html)
354
- - [lchownSync](https://uwx-node-modules.github.io/fsxt/functions/lchownSync.html)
355
- - [linkSync](https://uwx-node-modules.github.io/fsxt/functions/linkSync.html)
356
- - [lstatSync](https://uwx-node-modules.github.io/fsxt/functions/lstatSync.html)
357
- - [lutimesSync](https://uwx-node-modules.github.io/fsxt/functions/lutimesSync.html)
358
- - [mkdirsSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirsSync.html)
359
- - [mkdtempSync](https://uwx-node-modules.github.io/fsxt/functions/mkdtempSync.html)
360
- - [opendirSync](https://uwx-node-modules.github.io/fsxt/functions/opendirSync.html)
361
- - [readLinesSync](https://uwx-node-modules.github.io/fsxt/functions/readLinesSync.html)
362
- - [readlinkSync](https://uwx-node-modules.github.io/fsxt/functions/readlinkSync.html)
363
- - [readSync](https://uwx-node-modules.github.io/fsxt/functions/readSync.html)
364
- - [readvSync](https://uwx-node-modules.github.io/fsxt/functions/readvSync.html)
365
- - [realpathSync](https://uwx-node-modules.github.io/fsxt/functions/realpathSync.html)
366
- - [removeSync](https://uwx-node-modules.github.io/fsxt/functions/removeSync.html)
367
- - [statfsSync](https://uwx-node-modules.github.io/fsxt/functions/statfsSync.html)
368
- - [utimesSync](https://uwx-node-modules.github.io/fsxt/functions/utimesSync.html)
369
- - [writevSync](https://uwx-node-modules.github.io/fsxt/functions/writevSync.html)
370
-
371
- ## Bun Integration
372
-
373
- Relifso provides first-class support for Bun with automatic fallbacks to Node.js APIs. Here's how it works:
374
-
375
- ### Automatic Runtime Detection
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.
376
260
 
377
261
  ```ts
378
- import { isBun } from "@reliverse/relifso";
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)`
379
273
 
380
- if (isBun) {
381
- console.log("Running in Bun!");
382
- } else {
383
- console.log("Running in Node.js");
274
+ Check if a path exists.
275
+
276
+ ```ts
277
+ if (await fs.pathExists("config.json")) {
278
+ const config = await fs.readJson("config.json");
384
279
  }
385
280
  ```
386
281
 
387
- ### Optimized File Operations
282
+ #### `sizeOf(path, options?)`
388
283
 
389
- When running in Bun, relifso automatically uses Bun's optimized file system APIs:
284
+ Get the total size of a file or directory.
390
285
 
391
- - `Bun.file()` for file operations
392
- - Native file existence checks
393
- - Optimized file size and type detection
394
- - Fast last modified time access
286
+ ```ts
287
+ // File size
288
+ const fileSize = await fs.sizeOf("large-file.zip");
395
289
 
396
- ### Graceful Fallbacks
290
+ // Directory size (recursive)
291
+ const dirSize = await fs.sizeOf("node_modules");
397
292
 
398
- All Bun-specific operations include automatic fallbacks to Node.js APIs:
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.
399
302
 
400
303
  ```ts
401
- import { getStats } from "@reliverse/relifso";
304
+ // Copy file
305
+ await fs.copy("src/index.ts", "dist/index.js");
402
306
 
403
- // In Bun: Uses Bun.file() for faster stats
404
- // In Node.js: Falls back to fs.stat()
405
- const stats = await getStats("file.txt");
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
+ });
406
316
  ```
407
317
 
408
- ### Available Bun-Specific Utilities
318
+ #### `move(source, destination, options?)`
409
319
 
410
- - `getFile(path)` - Get a Bun file reference
411
- - `exists(path)` - Check file existence using Bun's API
412
- - `size(path)` - Get file size using Bun's API
413
- - `type(path)` - Get file MIME type using Bun's API
414
- - `lastModified(path)` - Get file last modified time
415
- - `getStats(path)` - Get file stats with Bun optimization
416
- - `getStatsSync(path)` - Synchronous version of getStats
320
+ Move (rename) a file or directory.
417
321
 
418
- ## Contributing
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
+ ```
419
332
 
420
- ...
333
+ ### Link Operations
421
334
 
422
- ## TODO
335
+ #### `ensureLink(source, destination)`
423
336
 
424
- - [x] Create usage example in [./example/e-relifso.ts](./e-relifso.ts) and [./example/e-pathkit.ts](./e-pathkit.ts)
425
- - [x] Ensure [./example/e-relifso.ts](./example/e-relifso.ts) and [./example/e-pathkit.ts](./example/e-pathkit.ts) works 100% correctly
426
- - [ ] Consider using [@reliverse/repath](https://github.com/reliverse/repath) instead of just `node:path`.
427
- - [ ] Pass all `fs-extra` tests with Bun (+ fix & improve them).
428
- - [ ] In [docs.reliverse.org](https://docs.reliverse.org) implement feature and performance comparison table with `fs-extra`.
337
+ Create a hard link, ensuring the destination exists.
429
338
 
430
- ## Shoutouts
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
+ ```
431
354
 
432
- Relifso wouldn't be so cool without these gems:
355
+ ### Utility Functions
433
356
 
434
- - [`node:fs`](https://nodejs.org/api/fs.html)+[`node:path`](https://nodejs.org/api/path.html) — origins
435
- - [`fs-extra`](https://github.com/jprichardson/node-fs-extra) — classic, reliable
436
- - [`fsxt`](https://github.com/uwx-node-modules/fsxt) — full fs-extra overhaul
357
+ #### `touch(path, options?)`
437
358
 
438
- ## Show Some Love
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
+ ```
439
444
 
440
- If `@reliverse/relifso` reduced the number of lines in your codebase:
445
+ ## Requirements
441
446
 
442
- - [Star it on GitHub](https://github.com/reliverse/relifso)
443
- - 💖 [Sponsor @blefnk](https://github.com/sponsors/blefnk)
444
- - 🧙 Recommend it to your dev friends
447
+ - **Bun** >= 1.0 (recommended for optimal performance)
448
+ - **Node.js** >= 18 (fallback to `node:fs` when Bun APIs aren't available)
445
449
 
446
450
  ## License
447
451
 
448
- [MIT](./LICENSE) © 2025 [Nazar Kornienko (blefnk)](https://github.com/blefnk)
452
+ MIT