@reliverse/relifso 1.4.5 → 2.2.8

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 +365 -447
  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,534 +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
- - 🔧 Built-in JSON repair — automatically fixes common JSON formatting issues
22
-
23
- ## 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
24
17
 
25
18
  ```bash
26
- # bun • pnpm • yarn • npm
27
19
  bun add @reliverse/relifso
28
20
  ```
29
21
 
30
- **Migrate**:
22
+ ## Quick Start
31
23
 
32
- ```bash
33
- bun rm fs-extra
34
- bun rm @types/fs-extra
35
- # soon:
36
- # bun add -D @reliverse/dler
37
- # bun dler migrate fs-relifso
38
- ```
39
-
40
- **Pro Tip**: _Use Ctrl+Shift+H to replace `fs-extra` with `@reliverse/relifso` in your project._
41
-
42
- ### Core Features
43
-
44
- - **File Operations**
45
- - Read/write files with various encodings
46
- - Copy/move files and directories
47
- - Create/remove files and directories
48
- - File existence checks
49
- - File stats and metadata access
50
-
51
- - **Directory Operations**
52
- - Create nested directories
53
- - Empty directories
54
- - Directory traversal with `dive`
55
- - Directory existence checks
56
-
57
- - **JSON Operations**
58
- - Read/write JSON files with validation
59
- - JSON repair and validation utilities
60
- - JSON streaming support
61
- - JSONC (JSON with Comments) support
62
- - Automatic JSON repair for common issues:
63
- - Missing quotes around keys
64
- - Missing escape characters
65
- - Missing commas and closing brackets
66
- - Truncated JSON
67
- - Single quotes to double quotes conversion
68
- - Special quote characters normalization
69
- - Special whitespace normalization
70
- - Python constants (None, True, False) conversion
71
- - Trailing comma removal
72
- - Comment stripping
73
- - Code block stripping
74
- - Array/object ellipsis removal
75
- - JSONP notation removal
76
- - MongoDB data type conversion
77
- - String concatenation
78
- - Newline-delimited JSON conversion
79
-
80
- - **Bun Optimizations**
81
- - Automatic runtime detection
82
- - Optimized file operations using Bun APIs
83
- - Fast file stats and metadata access
84
- - Graceful fallbacks to Node.js APIs
85
-
86
- - **Utility Functions**
87
- - File type detection
88
- - Hidden file attribute handling
89
- - Directory emptiness checks
90
- - File size and last modified time access
91
-
92
- ### Error Handling
93
-
94
- - Graceful handling of common filesystem errors
95
- - Consistent error types and messages
96
- - Automatic error recovery where possible
97
- - Detailed error information for debugging
98
- - Runtime detection errors
99
- - File operation failures
100
- - All Bun-specific operations include proper error handling
101
- - Automatic fallback from Bun to Node.js APIs when needed
102
-
103
- ## Usage
104
-
105
- 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`.
106
-
107
- Relifso works just like `fs-extra` — every method is promise-first, ergonomic, and future-ready.
24
+ ### Default Import
108
25
 
109
26
  ```ts
110
- import { copy, pathExists, remove } from "@reliverse/relifso";
27
+ import fs from "@reliverse/relifso";
111
28
 
112
- await copy("src/index.ts", "dist/index.ts");
29
+ // Read and write files
30
+ const content = await fs.readFile("package.json", { encoding: "utf8" });
31
+ await fs.writeFile("output.txt", "Hello, Bun!");
113
32
 
114
- if (await pathExists("dist/index.ts")) {
115
- await remove("dist/index.ts");
116
- }
117
- ```
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");
118
41
 
119
- - Everything's bundled — modern, async, and type-safe.
120
- - 🧼 No more boilerplate like `promisify(fs.removeSync)` or using `mkdirp`, `ncp`, or `rimraf`.
121
- - 🌱 No more weird `try/catch` for common errors like "file not found."
122
- - ✌️ Just clean, predictable APIs built for 2025 and beyond.
42
+ // Copy and move
43
+ await fs.copy("src", "dist");
44
+ await fs.move("old.txt", "new.txt");
45
+ ```
123
46
 
124
- ## Example
47
+ ### Named Imports
125
48
 
126
49
  ```ts
127
50
  import {
128
- ensureDir,
129
- outputJson,
51
+ readFile,
52
+ writeFile,
130
53
  readJson,
54
+ writeJson,
55
+ ensureDir,
56
+ copy,
131
57
  remove,
132
58
  } from "@reliverse/relifso";
133
59
 
134
- const path = "./.reliverse/config.json";
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
135
68
 
136
- await ensureDir(".reliverse");
137
- await outputJson(path, { hello: "world" });
69
+ #### `readFile(path, options?)`
138
70
 
139
- const config = await readJson(path);
140
- console.log(config); // { hello: 'world' }
71
+ Read a file as a string with various encodings or binary (`Uint8Array`).
141
72
 
142
- await remove(".reliverse");
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" });
143
85
  ```
144
86
 
145
- ## Run Example
87
+ #### `writeFile(destination, data, options?)`
146
88
 
147
- Install this repository locally and run the example by using `bun dev`:
89
+ Write data to a file. Accepts strings, `Uint8Array`, `Blob`, or `BunFile`.
148
90
 
149
- ```bash
150
- $ bun e-mod.ts
151
- ✓ Running examples with Bun...
152
- Created directory ./tests-runtime
153
- [env] writeJson was successfully executed in Bun (for JSON)
154
- Wrote JSON tests-runtime\config.json
155
- [env] readJson was successfully executed in Bun
156
- Read JSON {"hello":"world","ts":"2025-06-02T19:01:53.291Z"}
157
- [env] copy was successfully executed in Bun
158
- Moved Copied (with overwrite) tests-runtime\config.old.json → tests-runtime\config.copy.json
159
- [env] readFile was successfully executed in Bun
160
- Wrote & read text file Hello Relifso!
161
- [env] writeFile was successfully executed in Bun
162
- [env] writeFile was successfully executed in Bun
163
- Ensured nested & output files
164
- [env] writeJson was successfully executed in Bun (for JSON)
165
- [env] readJson was successfully executed in Bun
166
- writeJson / readJson round-trip {"foo":"bar"}
167
- [env] writeJson was successfully executed in Bun (for JSONC)
168
- Wrote JSONC tests-runtime\config.jsonc
169
- [env] readJson was successfully executed in Bun
170
- Read JSONC {
171
- "name": "relifso",
172
- "version": "1.0.0",
173
- "features": [
174
- "file operations",
175
- "directory operations",
176
- "JSONC support"
177
- ],
178
- "settings": {
179
- "debug": true,
180
- "verbose": false
181
- }
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;
182
136
  }
183
- Emptied directory tests-runtime\empty-me
184
- [env] writeFileSync was successfully executed in Bun
185
- [env] writeJsonSync was successfully executed in Bun (for JSON)
186
- Sync JSON round-trip {"sync":true}
187
- [env] copySync was successfully executed in Bun
188
- copySync → moveSync → removeSync chain complete
189
- Directory structure via dive
190
- • tests-runtime\config-sync.json
191
- • tests-runtime\config.copy.json
192
- • tests-runtime\config.jsonc
193
- • tests-runtime\config.old.json
194
- • tests-runtime\config2.json
195
- • tests-runtime\hello.txt
196
- • tests-runtime\nested\deep\file.txt
197
- • tests-runtime\output-file.txt
198
- Directory structure via diveSync
199
- • tests-runtime\config-sync.json
200
- • tests-runtime\config.copy.json
201
- • tests-runtime\config.jsonc
202
- • tests-runtime\config.old.json
203
- • tests-runtime\config2.json
204
- • tests-runtime\hello.txt
205
- • tests-runtime\nested\deep\file.txt
206
- • tests-runtime\output-file.txt
207
- Removed directory ./tests-runtime
137
+
138
+ const pkg = await fs.readJson<PackageJson>("package.json");
139
+ console.log(pkg.name); // Type-safe access
208
140
  ```
209
141
 
210
- ## Sync vs Async vs Legacy
142
+ #### `readJSONSync<T>(path)`
211
143
 
212
- You choose your flavor:
144
+ Read and parse a JSON file synchronously.
213
145
 
214
146
  ```ts
215
- // Async/Await
216
- await copy("a.txt", "b.txt");
147
+ interface PackageJson {
148
+ name: string;
149
+ version: string;
150
+ }
217
151
 
218
- // Sync
219
- copySync("a.txt", "b.txt");
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
+ ```
220
156
 
221
- // Callback (legacy-style)
222
- copy("a.txt", "b.txt", err => {
223
- if (err) console.error(err);
224
- });
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 });
225
166
  ```
226
167
 
227
- All async methods return a `Promise` if no callback is passed.
228
-
229
- ## Fully Typed, Fully Modern
230
-
231
- - Written in modern ESM
232
- - Minimal dependencies
233
- - Full TypeScript declarations
234
- - Compatible with Node.js 16+, best with 22+
235
- - Async methods are built from the sync versions — no wrappers, no bloat
236
-
237
- ## What's Inside?
238
-
239
- - All async methods follow the `Promise` pattern by default.
240
- - All sync methods are safe and throw errors when needed.
241
-
242
- ### Async (recommended)
243
-
244
- #### Common Async Methods
245
-
246
- - [access](https://uwx-node-modules.github.io/fsxt/functions/access.html)
247
- - [appendFile](https://uwx-node-modules.github.io/fsxt/functions/appendFile.html)
248
- - [copy](https://uwx-node-modules.github.io/fsxt/functions/copy.html)
249
- - [copyFile](https://uwx-node-modules.github.io/fsxt/functions/copyFile.html)
250
- - [cp](https://uwx-node-modules.github.io/fsxt/functions/cp.html)
251
- - [createReadStream](https://uwx-node-modules.github.io/fsxt/functions/createReadStream.html)
252
- - [createWriteStream](https://uwx-node-modules.github.io/fsxt/functions/createWriteStream.html)
253
- - [ensureFile](https://uwx-node-modules.github.io/fsxt/functions/ensureFile.html)
254
- - [exists](https://uwx-node-modules.github.io/fsxt/functions/exists.html)
255
- - [mkdir](https://uwx-node-modules.github.io/fsxt/functions/mkdir.html)
256
- - [mkdirs](https://uwx-node-modules.github.io/fsxt/functions/mkdirs.html)
257
- - [move](https://uwx-node-modules.github.io/fsxt/functions/move.html)
258
- - [open](https://uwx-node-modules.github.io/fsxt/functions/open.html)
259
- - [outputFile](https://uwx-node-modules.github.io/fsxt/functions/outputFile.html)
260
- - [outputJson](https://uwx-node-modules.github.io/fsxt/functions/outputJson.html)
261
- - [read](https://uwx-node-modules.github.io/fsxt/functions/read.html)
262
- - [readdir](https://uwx-node-modules.github.io/fsxt/functions/readdir.html)
263
- - [readFile](https://uwx-node-modules.github.io/fsxt/functions/readFile.html)
264
- - [readJson](https://uwx-node-modules.github.io/fsxt/functions/readJson.html)
265
- - [readLines](https://uwx-node-modules.github.io/fsxt/functions/readLines.html)
266
- - [readText](https://uwx-node-modules.github.io/fsxt/functions/readText.html)
267
- - [rename](https://uwx-node-modules.github.io/fsxt/functions/rename.html)
268
- - [rm](https://uwx-node-modules.github.io/fsxt/functions/rm.html)
269
- - [rmdir](https://uwx-node-modules.github.io/fsxt/functions/rmdir.html)
270
- - [stat](https://uwx-node-modules.github.io/fsxt/functions/stat.html)
271
- - [symlink](https://uwx-node-modules.github.io/fsxt/functions/symlink.html)
272
- - [truncate](https://uwx-node-modules.github.io/fsxt/functions/truncate.html)
273
- - [unlink](https://uwx-node-modules.github.io/fsxt/functions/unlink.html)
274
- - [watch](https://uwx-node-modules.github.io/fsxt/functions/watch.html)
275
- - [watchFile](https://uwx-node-modules.github.io/fsxt/functions/watchFile.html)
276
- - [write](https://uwx-node-modules.github.io/fsxt/functions/write.html)
277
- - [writeFile](https://uwx-node-modules.github.io/fsxt/functions/writeFile.html)
278
- - [writeJson](https://uwx-node-modules.github.io/fsxt/functions/writeJson.html)
279
-
280
- #### Less Commonly Used Async Methods
281
-
282
- - [chmod](https://uwx-node-modules.github.io/fsxt/functions/chmod.html)
283
- - [chown](https://uwx-node-modules.github.io/fsxt/functions/chown.html)
284
- - [close](https://uwx-node-modules.github.io/fsxt/functions/close.html)
285
- - [dive](https://uwx-node-modules.github.io/fsxt/functions/dive.html)
286
- - [emptyDir](https://uwx-node-modules.github.io/fsxt/functions/emptyDir.html)
287
- - [ensureLink](https://uwx-node-modules.github.io/fsxt/functions/ensureLink.html)
288
- - [ensureSymlink](https://uwx-node-modules.github.io/fsxt/functions/ensureSymlink.html)
289
- - [fchmod](https://uwx-node-modules.github.io/fsxt/functions/fchmod.html)
290
- - [fchown](https://uwx-node-modules.github.io/fsxt/functions/fchown.html)
291
- - [forEachChild](https://uwx-node-modules.github.io/fsxt/functions/forEachChild.html)
292
- - [fstat](https://uwx-node-modules.github.io/fsxt/functions/fstat.html)
293
- - [ftruncate](https://uwx-node-modules.github.io/fsxt/functions/ftruncate.html)
294
- - [futimes](https://uwx-node-modules.github.io/fsxt/functions/futimes.html)
295
- - [gracefulify](https://uwx-node-modules.github.io/fsxt/functions/gracefulify.html)
296
- - [isDirectory](https://uwx-node-modules.github.io/fsxt/functions/isDirectory.html)
297
- - [isSymlink](https://uwx-node-modules.github.io/fsxt/functions/isSymlink.html)
298
- - [~~lchmod~~](https://uwx-node-modules.github.io/fsxt/functions/lchmod.html)
299
- - [lchown](https://uwx-node-modules.github.io/fsxt/functions/lchown.html)
300
- - [`link`](https://uwx-node-modules.github.io/fsxt/functions/link.html)
301
- - [lstat](https://uwx-node-modules.github.io/fsxt/functions/lstat.html)
302
- - [lutimes](https://uwx-node-modules.github.io/fsxt/functions/lutimes.html)
303
- - [mapChildren](https://uwx-node-modules.github.io/fsxt/functions/mapChildren.html)
304
- - [mapStructure](https://uwx-node-modules.github.io/fsxt/functions/mapStructure.html)
305
- - [mapStructureOrdered](https://uwx-node-modules.github.io/fsxt/functions/mapStructureOrdered.html)
306
- - [mkdtemp](https://uwx-node-modules.github.io/fsxt/functions/mkdtemp.html)
307
- - [openAsBlob](https://uwx-node-modules.github.io/fsxt/functions/openAsBlob.html)
308
- - [opendir](https://uwx-node-modules.github.io/fsxt/functions/opendir.html)
309
- - [readv](https://uwx-node-modules.github.io/fsxt/functions/readv.html)
310
- - [realpath](https://uwx-node-modules.github.io/fsxt/functions/realpath.html)
311
- - [remove](https://uwx-node-modules.github.io/fsxt/functions/remove.html)
312
- - [resolve](https://uwx-node-modules.github.io/fsxt/functions/resolve.html)
313
- - [statfs](https://uwx-node-modules.github.io/fsxt/functions/statfs.html)
314
- - [unwatchFile](https://uwx-node-modules.github.io/fsxt/functions/unwatchFile.html)
315
- - [utimes](https://uwx-node-modules.github.io/fsxt/functions/utimes.html)
316
- - [vacuum](https://uwx-node-modules.github.io/fsxt/functions/vacuum.html)
317
- - [writev](https://uwx-node-modules.github.io/fsxt/functions/writev.html)
318
-
319
- ### Sync
320
-
321
- #### Common Sync Methods
322
-
323
- - [accessSync](https://uwx-node-modules.github.io/fsxt/functions/accessSync.html)
324
- - [appendFileSync](https://uwx-node-modules.github.io/fsxt/functions/appendFileSync.html)
325
- - [copyFileSync](https://uwx-node-modules.github.io/fsxt/functions/copyFileSync.html)
326
- - [copySync](https://uwx-node-modules.github.io/fsxt/functions/copySync.html)
327
- - [cpSync](https://uwx-node-modules.github.io/fsxt/functions/cpSync.html)
328
- - [existsSync](https://uwx-node-modules.github.io/fsxt/functions/existsSync.html)
329
- - [mkdirSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirSync.html)
330
- - [mkdirsSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirsSync.html)
331
- - [moveSync](https://uwx-node-modules.github.io/fsxt/functions/moveSync.html)
332
- - [openSync](https://uwx-node-modules.github.io/fsxt/functions/openSync.html)
333
- - [outputFileSync](https://uwx-node-modules.github.io/fsxt/functions/outputFileSync.html)
334
- - [outputJsonSync](https://uwx-node-modules.github.io/fsxt/functions/outputJsonSync.html)
335
- - [readdirSync](https://uwx-node-modules.github.io/fsxt/functions/readdirSync.html)
336
- - [readFileSync](https://uwx-node-modules.github.io/fsxt/functions/readFileSync.html)
337
- - [readJsonSync](https://uwx-node-modules.github.io/fsxt/functions/readJsonSync.html)
338
- - [readTextSync](https://uwx-node-modules.github.io/fsxt/functions/readTextSync.html)
339
- - [renameSync](https://uwx-node-modules.github.io/fsxt/functions/renameSync.html)
340
- - [rmSync](https://uwx-node-modules.github.io/fsxt/functions/rmSync.html)
341
- - [rmdirSync](https://uwx-node-modules.github.io/fsxt/functions/rmdirSync.html)
342
- - [statSync](https://uwx-node-modules.github.io/fsxt/functions/statSync.html)
343
- - [symlinkSync](https://uwx-node-modules.github.io/fsxt/functions/symlinkSync.html)
344
- - [truncateSync](https://uwx-node-modules.github.io/fsxt/functions/truncateSync.html)
345
- - [unlinkSync](https://uwx-node-modules.github.io/fsxt/functions/unlinkSync.html)
346
- - [writeFileSync](https://uwx-node-modules.github.io/fsxt/functions/writeFileSync.html)
347
- - [writeJsonSync](https://uwx-node-modules.github.io/fsxt/functions/writeJsonSync.html)
348
- - [writeSync](https://uwx-node-modules.github.io/fsxt/functions/writeSync.html)
349
-
350
- #### Less Commonly Used Sync Methods
351
-
352
- - [chmodSync](https://uwx-node-modules.github.io/fsxt/functions/chmodSync.html)
353
- - [chownSync](https://uwx-node-modules.github.io/fsxt/functions/chownSync.html)
354
- - [closeSync](https://uwx-node-modules.github.io/fsxt/functions/closeSync.html)
355
- - [diveSync](https://uwx-node-modules.github.io/fsxt/functions/diveSync.html)
356
- - [emptyDirSync](https://uwx-node-modules.github.io/fsxt/functions/emptyDirSync.html)
357
- - [ensureFileSync](https://uwx-node-modules.github.io/fsxt/functions/ensureFileSync.html)
358
- - [ensureLinkSync](https://uwx-node-modules.github.io/fsxt/functions/ensureLinkSync.html)
359
- - [ensureSymlinkSync](https://uwx-node-modules.github.io/fsxt/functions/ensureSymlinkSync.html)
360
- - [fchmodSync](https://uwx-node-modules.github.io/fsxt/functions/fchmodSync.html)
361
- - [fchownSync](https://uwx-node-modules.github.io/fsxt/functions/fchownSync.html)
362
- - [fdatasync](https://uwx-node-modules.github.io/fsxt/functions/fdatasync.html)
363
- - [fdatasyncSync](https://uwx-node-modules.github.io/fsxt/functions/fdatasyncSync.html)
364
- - [forEachChildSync](https://uwx-node-modules.github.io/fsxt/functions/forEachChildSync.html)
365
- - [fstatSync](https://uwx-node-modules.github.io/fsxt/functions/fstatSync.html)
366
- - [fsync](https://uwx-node-modules.github.io/fsxt/functions/fsync.html)
367
- - [fsyncSync](https://uwx-node-modules.github.io/fsxt/functions/fsyncSync.html)
368
- - [ftruncateSync](https://uwx-node-modules.github.io/fsxt/functions/ftruncateSync.html)
369
- - [futimesSync](https://uwx-node-modules.github.io/fsxt/functions/futimesSync.html)
370
- - [isDirectorySync](https://uwx-node-modules.github.io/fsxt/functions/isDirectorySync.html)
371
- - [~~lchmodSync~~](https://uwx-node-modules.github.io/fsxt/functions/lchmodSync.html)
372
- - [lchownSync](https://uwx-node-modules.github.io/fsxt/functions/lchownSync.html)
373
- - [linkSync](https://uwx-node-modules.github.io/fsxt/functions/linkSync.html)
374
- - [lstatSync](https://uwx-node-modules.github.io/fsxt/functions/lstatSync.html)
375
- - [lutimesSync](https://uwx-node-modules.github.io/fsxt/functions/lutimesSync.html)
376
- - [mkdirsSync](https://uwx-node-modules.github.io/fsxt/functions/mkdirsSync.html)
377
- - [mkdtempSync](https://uwx-node-modules.github.io/fsxt/functions/mkdtempSync.html)
378
- - [opendirSync](https://uwx-node-modules.github.io/fsxt/functions/opendirSync.html)
379
- - [readLinesSync](https://uwx-node-modules.github.io/fsxt/functions/readLinesSync.html)
380
- - [readlinkSync](https://uwx-node-modules.github.io/fsxt/functions/readlinkSync.html)
381
- - [readSync](https://uwx-node-modules.github.io/fsxt/functions/readSync.html)
382
- - [readvSync](https://uwx-node-modules.github.io/fsxt/functions/readvSync.html)
383
- - [realpathSync](https://uwx-node-modules.github.io/fsxt/functions/realpathSync.html)
384
- - [removeSync](https://uwx-node-modules.github.io/fsxt/functions/removeSync.html)
385
- - [statfsSync](https://uwx-node-modules.github.io/fsxt/functions/statfsSync.html)
386
- - [utimesSync](https://uwx-node-modules.github.io/fsxt/functions/utimesSync.html)
387
- - [writevSync](https://uwx-node-modules.github.io/fsxt/functions/writevSync.html)
388
-
389
- ## Bun Integration
390
-
391
- Relifso provides first-class support for Bun with automatic fallbacks to Node.js APIs. Here's how it works:
392
-
393
- ### JSON Repair Integration
394
-
395
- Relifso includes built-in JSON repair capabilities powered by `jsonrepair`, providing robust handling of malformed JSON files. This integration is particularly useful when dealing with JSON files that may have formatting issues or come from various sources.
396
-
397
- #### Repair Features
398
-
399
- - **Automatic Repair**: Automatically fixes common JSON formatting issues without requiring manual intervention
400
- - **Streaming Support**: Handles infinitely large JSON documents through streaming
401
- - **Error Recovery**: Gracefully handles and repairs various JSON syntax errors
402
- - **Performance Optimized**: Efficient processing with configurable buffer sizes
403
-
404
- #### Usage Example
168
+ #### `outputFile(destination, data, options?)`
169
+
170
+ Write a file, automatically creating parent directories if needed.
405
171
 
406
172
  ```ts
407
- import { readJson, writeJson } from "@reliverse/relifso";
408
-
409
- // Reading a malformed JSON file
410
- const malformedJson = `{
411
- name: 'John', // Missing quotes and using single quotes
412
- age: 30,
413
- active: True, // Python-style boolean
414
- tags: ['dev', 'js', ...], // Trailing ellipsis
415
- metadata: {
416
- lastLogin: ISODate("2024-03-20T10:00:00Z") // MongoDB date
417
- }
418
- }`;
419
-
420
- // The JSON will be automatically repaired when reading
421
- const data = await readJson("config.json");
422
- console.log(data);
423
- // Output: Properly formatted JSON with all issues fixed
424
-
425
- // Writing JSON with automatic repair
426
- await writeJson("output.json", data, { repair: true });
173
+ // Creates "build/assets" directory if it doesn't exist
174
+ await fs.outputFile("build/assets/style.css", "body { margin: 0; }");
427
175
  ```
428
176
 
429
- #### Streaming Support
177
+ #### `outputJson(destination, data, options?)`
430
178
 
431
- For large JSON files, you can use the streaming API:
179
+ Write JSON to a file, automatically creating parent directories.
432
180
 
433
181
  ```ts
434
- import { createReadStream, createWriteStream } from "@reliverse/relifso";
182
+ await fs.outputJson("build/meta.json", { version: "1.0.0" });
183
+ ```
184
+
185
+ ### Directory Operations
186
+
187
+ #### `ensureDir(path)`
435
188
 
436
- const inputStream = createReadStream("./data/broken.json");
437
- const outputStream = createWriteStream("./data/repaired.json");
189
+ Ensure a directory exists, creating it and any necessary parent directories.
438
190
 
439
- // The repair happens automatically during the stream
440
- await pipeline(inputStream, outputStream);
191
+ ```ts
192
+ await fs.ensureDir("dist/assets/images");
193
+ // Creates: dist/assets/images (and all parent directories)
441
194
  ```
442
195
 
443
- #### Configuration Options
196
+ #### `mkdirp(path)`
197
+
198
+ Alias for `ensureDir`.
444
199
 
445
- When using JSON operations, you can configure the repair behavior:
200
+ #### `ensureFile(path)`
201
+
202
+ Ensure a file exists, creating it and any necessary parent directories.
446
203
 
447
204
  ```ts
448
- import { readJson } from "@reliverse/relifso";
449
-
450
- const options = {
451
- repair: true, // Enable automatic repair
452
- streaming: {
453
- chunkSize: 65536, // Size of output chunks
454
- bufferSize: 65536 // Size of repair buffer
455
- }
456
- };
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");
457
216
 
458
- const data = await readJson("large.json", options);
217
+ // With file types
218
+ const entries = await fs.readdir("src", { withFileTypes: true });
459
219
  ```
460
220
 
461
- ### Automatic Runtime Detection
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.
462
247
 
463
248
  ```ts
464
- import { isBun } from "@reliverse/relifso";
249
+ await fs.emptyDir("temp");
465
250
 
466
- if (isBun) {
467
- console.log("Running in Bun!");
468
- } else {
469
- console.log("Running in Node.js");
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");
470
279
  }
471
280
  ```
472
281
 
473
- ### Optimized File Operations
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
474
298
 
475
- When running in Bun, relifso automatically uses Bun's optimized file system APIs:
299
+ #### `copy(source, destination, options?)`
476
300
 
477
- - `Bun.file()` for file operations
478
- - Native file existence checks
479
- - Optimized file size and type detection
480
- - Fast last modified time access
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
+ ```
481
317
 
482
- ### Graceful Fallbacks
318
+ #### `move(source, destination, options?)`
483
319
 
484
- All Bun-specific operations include automatic fallbacks to Node.js APIs:
320
+ Move (rename) a file or directory.
485
321
 
486
322
  ```ts
487
- import { getStats } from "@reliverse/relifso";
323
+ // Move file
324
+ await fs.move("old.txt", "new.txt");
488
325
 
489
- // In Bun: Uses Bun.file() for faster stats
490
- // In Node.js: Falls back to fs.stat()
491
- const stats = await getStats("file.txt");
326
+ // Move directory
327
+ await fs.move("src", "lib");
328
+
329
+ // With options
330
+ await fs.move("old.txt", "new.txt", { overwrite: true });
492
331
  ```
493
332
 
494
- ### Available Bun-Specific Utilities
333
+ ### Link Operations
334
+
335
+ #### `ensureLink(source, destination)`
495
336
 
496
- - `getFile(path)` - Get a Bun file reference
497
- - `exists(path)` - Check file existence using Bun's API
498
- - `size(path)` - Get file size using Bun's API
499
- - `type(path)` - Get file MIME type using Bun's API
500
- - `lastModified(path)` - Get file last modified time
501
- - `getStats(path)` - Get file stats with Bun optimization
502
- - `getStatsSync(path)` - Synchronous version of getStats
337
+ Create a hard link, ensuring the destination exists.
338
+
339
+ ```ts
340
+ await fs.ensureLink("original.txt", "link.txt");
341
+ ```
503
342
 
504
- ## Contributing
343
+ #### `ensureSymlink(source, destination, options?)`
505
344
 
506
- ...
345
+ Create a symbolic link, ensuring the destination exists.
507
346
 
508
- ## TODO
347
+ ```ts
348
+ // Unix/Linux/Mac
349
+ await fs.ensureSymlink("target", "link");
509
350
 
510
- - [x] Create usage example in [./example/e-relifso.ts](./example/e-relifso.ts) and [./example/e-pathkit.ts](./example/e-pathkit.ts)
511
- - [x] Ensure [./example/e-relifso.ts](./example/e-relifso.ts) and [./example/e-pathkit.ts](./example/e-pathkit.ts) works 100% correctly
512
- - [ ] Consider using [@reliverse/repath](https://github.com/reliverse/repath) instead of just `node:path`.
513
- - [ ] Pass all `fs-extra` tests with Bun (+ fix & improve them).
514
- - [ ] In [docs.reliverse.org](https://docs.reliverse.org) implement feature and performance comparison table with `fs-extra`.
351
+ // Windows (automatic junction detection)
352
+ await fs.ensureSymlink("target", "link", { type: "dir" });
353
+ ```
515
354
 
516
- ## Shoutouts
355
+ ### Utility Functions
517
356
 
518
- Relifso wouldn't be so cool without these gems:
357
+ #### `touch(path, options?)`
519
358
 
520
- - [`node:fs`](https://nodejs.org/api/fs.html)+[`node:path`](https://nodejs.org/api/path.html) origins
521
- - [`fs-extra`](https://github.com/jprichardson/node-fs-extra) — classic, reliable
522
- - [`fsxt`](https://github.com/uwx-node-modules/fsxt) — full fs-extra overhaul
359
+ Update file access and modification times, creating the file if it doesn't exist.
523
360
 
524
- ## Show Some Love
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
+ ```
525
444
 
526
- If `@reliverse/relifso` reduced the number of lines in your codebase:
445
+ ## Requirements
527
446
 
528
- - [Star it on GitHub](https://github.com/reliverse/relifso)
529
- - 💖 [Sponsor @blefnk](https://github.com/sponsors/blefnk)
530
- - 🧙 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)
531
449
 
532
450
  ## License
533
451
 
534
- [MIT](./LICENSE) © 2025 [Nazar Kornienko (blefnk)](https://github.com/blefnk)
452
+ MIT