@reliverse/relifso 1.4.1 โ†’ 1.4.2

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
@@ -13,7 +13,7 @@
13
13
  - ๐Ÿงฏ Gracefully handles errors like `EMFILE` (reading or writing a lot of files at once) and other edge cases
14
14
  - ๐Ÿ“š Consistent error-first behavior โ€” even for legacy APIs like `fs.exists()`
15
15
  - ๐Ÿ“ฆ First-class ESM and full TypeScript support โ€” no config hacks required
16
- - ๐Ÿงผ Zero bloat โ€” small size ([6 kB](https://bundlephobia.com/package/@reliverse/relifso@latest)), zero deps, modern code, no monkey-patching
16
+ - ๐Ÿงผ Zero bloat โ€” small size, zero deps, modern code, no monkey-patching
17
17
  - ๐ŸŽฏ Supports all Node.js v16+ features โ€” optimized for Node.js v22+
18
18
  - ๐Ÿงช Soon: Ready for upcoming Node.js v22+ experimental features
19
19
  - โœŒ๏ธ Bun v1.2+ ready โ€” ships with Bun-aware enhancements out of the box
@@ -10,9 +10,9 @@ export interface ReadFileOptions {
10
10
  *
11
11
  * @param path - The path to the file.
12
12
  * @param options - Options for reading the file. Can be an encoding string or an object.
13
- * @returns The contents of the file.
13
+ * @returns The contents of the file as a string.
14
14
  */
15
- export declare function readFileSync(path: string, options?: BufferEncoding | ReadFileOptions): string | Buffer;
15
+ export declare function readFileSync(path: string, options?: BufferEncoding | ReadFileOptions): string;
16
16
  export declare function readFileSync(path: string, encoding: BufferEncoding): string;
17
17
  export declare function readFileSync(path: string, options: {
18
18
  encoding: BufferEncoding;
@@ -22,9 +22,9 @@ export declare function readFileSync(path: string, options: {
22
22
  *
23
23
  * @param path - The path to the file.
24
24
  * @param options - Options for reading the file. Can be an encoding string or an object.
25
- * @returns A promise that resolves with the contents of the file.
25
+ * @returns A promise that resolves with the contents of the file as a string.
26
26
  */
27
- export declare function readFile(path: string, options?: BufferEncoding | ReadFileOptions): Promise<string | Buffer>;
27
+ export declare function readFile(path: string, options?: BufferEncoding | ReadFileOptions): Promise<string>;
28
28
  export declare function readFile(path: string, encoding: BufferEncoding): Promise<string>;
29
29
  export declare function readFile(path: string, options: {
30
30
  encoding: BufferEncoding;
@@ -38,13 +38,13 @@ export function readFileSync(path, options) {
38
38
  if (buffer instanceof Promise) {
39
39
  throw new Error("Bun's arrayBuffer() returned a Promise in sync context");
40
40
  }
41
- return Buffer.from(buffer);
41
+ return Buffer.from(buffer).toString(encoding || "utf8");
42
42
  } catch (_error) {
43
43
  const text = file.text();
44
44
  if (text instanceof Promise) {
45
45
  throw new Error("Bun's text() returned a Promise in sync context");
46
46
  }
47
- return Buffer.from(text);
47
+ return text;
48
48
  }
49
49
  } catch (error) {
50
50
  }
@@ -52,7 +52,7 @@ export function readFileSync(path, options) {
52
52
  if (encoding) {
53
53
  return nodeReadFileSync(path, { encoding, flag });
54
54
  }
55
- return nodeReadFileSync(path, { encoding: null, flag });
55
+ return nodeReadFileSync(path, { encoding: "utf8", flag });
56
56
  }
57
57
  export async function readFile(path, options) {
58
58
  let encoding;
@@ -77,10 +77,10 @@ export async function readFile(path, options) {
77
77
  const result = await file.text();
78
78
  if (isJson) {
79
79
  try {
80
- return JSON.parse(result, reviver);
80
+ return JSON.stringify(JSON.parse(result, reviver));
81
81
  } catch (_parseError) {
82
82
  const repaired = jsonrepair(result);
83
- return JSON.parse(repaired, reviver);
83
+ return JSON.stringify(JSON.parse(repaired, reviver));
84
84
  }
85
85
  }
86
86
  return result;
@@ -89,10 +89,10 @@ export async function readFile(path, options) {
89
89
  const text = Buffer.from(buffer).toString(encoding);
90
90
  if (isJson) {
91
91
  try {
92
- return JSON.parse(text, reviver);
92
+ return JSON.stringify(JSON.parse(text, reviver));
93
93
  } catch (_parseError) {
94
94
  const repaired = jsonrepair(text);
95
- return JSON.parse(repaired, reviver);
95
+ return JSON.stringify(JSON.parse(repaired, reviver));
96
96
  }
97
97
  }
98
98
  return text;
@@ -100,27 +100,27 @@ export async function readFile(path, options) {
100
100
  }
101
101
  try {
102
102
  const buffer = await file.arrayBuffer();
103
+ const text = Buffer.from(buffer).toString(encoding || "utf8");
103
104
  if (isJson) {
104
- const text = Buffer.from(buffer).toString();
105
105
  try {
106
- return JSON.parse(text, reviver);
106
+ return JSON.stringify(JSON.parse(text, reviver));
107
107
  } catch (_parseError) {
108
108
  const repaired = jsonrepair(text);
109
- return JSON.parse(repaired, reviver);
109
+ return JSON.stringify(JSON.parse(repaired, reviver));
110
110
  }
111
111
  }
112
- return Buffer.from(buffer);
112
+ return text;
113
113
  } catch (_error) {
114
114
  const text = await file.text();
115
115
  if (isJson) {
116
116
  try {
117
- return JSON.parse(text, reviver);
117
+ return JSON.stringify(JSON.parse(text, reviver));
118
118
  } catch (_parseError) {
119
119
  const repaired = jsonrepair(text);
120
- return JSON.parse(repaired, reviver);
120
+ return JSON.stringify(JSON.parse(repaired, reviver));
121
121
  }
122
122
  }
123
- return Buffer.from(text);
123
+ return text;
124
124
  }
125
125
  } catch (error) {
126
126
  }
@@ -139,10 +139,10 @@ export async function readFile(path, options) {
139
139
  const text = chunks.join("");
140
140
  if (isJson) {
141
141
  try {
142
- return JSON.parse(text, reviver);
142
+ return JSON.stringify(JSON.parse(text, reviver));
143
143
  } catch (_parseError) {
144
144
  const repaired = jsonrepair(text);
145
- return JSON.parse(repaired, reviver);
145
+ return JSON.stringify(JSON.parse(repaired, reviver));
146
146
  }
147
147
  }
148
148
  return text;
@@ -153,13 +153,13 @@ export async function readFile(path, options) {
153
153
  const text = await nodeReadFileAsync(path, { encoding, flag });
154
154
  if (isJson) {
155
155
  try {
156
- return JSON.parse(text, reviver);
156
+ return JSON.stringify(JSON.parse(text, reviver));
157
157
  } catch (_parseError) {
158
158
  const repaired = jsonrepair(text);
159
- return JSON.parse(repaired, reviver);
159
+ return JSON.stringify(JSON.parse(repaired, reviver));
160
160
  }
161
161
  }
162
162
  return text;
163
163
  }
164
- return nodeReadFileAsync(path, { encoding: null, flag });
164
+ return await nodeReadFileAsync(path, { encoding: "utf8", flag });
165
165
  }
@@ -15,16 +15,16 @@ type WriteTarget = PathLike | number | URL | WriteStream;
15
15
  * Ensures the directory exists before writing.
16
16
  *
17
17
  * @param file - Path to the file, file descriptor, URL, or special streams (stdout/stderr).
18
- * @param data - The data to write. Can be a string, Buffer, Uint8Array, Blob, Response, or other ArrayBufferView.
18
+ * @param data - The data to write. Will be converted to string if not already a string.
19
19
  * @param options - Options for writing the file. Can be an encoding string or an object.
20
20
  */
21
- export declare function writeFileSync(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response, options?: WriteFileOptions): void;
21
+ export declare function writeFileSync(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response | unknown, options?: WriteFileOptions): void;
22
22
  /**
23
23
  * Asynchronously writes data to a file, replacing the file if it already exists.
24
24
  * Ensures the directory exists before writing.
25
25
  *
26
26
  * @param file - Path to the file, file descriptor, URL, or special streams (stdout/stderr).
27
- * @param data - The data to write. Can be a string, Buffer, Uint8Array, Blob, Response, or other ArrayBufferView.
27
+ * @param data - The data to write. Will be converted to string if not already a string.
28
28
  * @param options - Options for writing the file. Can be an encoding string or an object.
29
29
  */
30
30
  export declare function writeFile(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response | unknown, options?: WriteFileOptions): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import { writeFileSync as nodeWriteFileSync, createWriteStream } from "node:fs";
2
- import { mkdir, writeFile as nodeWriteFileAsync, stat } from "node:fs/promises";
2
+ import { mkdir, writeFile as nodeWriteFileAsync } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { Transform } from "node:stream";
5
5
  import { pipeline } from "node:stream/promises";
@@ -17,45 +17,53 @@ function isPathLike(target) {
17
17
  return !isStdStream(target) && !isFileDescriptor(target) && !(target instanceof URL);
18
18
  }
19
19
  export function writeFileSync(file, data, options) {
20
- if (isStdStream(file)) {
21
- if (typeof data === "string") {
22
- file.write(data);
23
- } else if (data instanceof Uint8Array) {
24
- file.write(data);
25
- } else if (data instanceof Blob || data instanceof Response) {
26
- throw new Error("Blob and Response are not supported for stdout/stderr in sync context");
27
- } else if (data instanceof ArrayBuffer) {
28
- file.write(Buffer.from(new Uint8Array(data)));
29
- } else if (ArrayBuffer.isView(data)) {
30
- file.write(Buffer.from(data.buffer, data.byteOffset, data.byteLength));
31
- } else {
32
- throw new Error("Unsupported data type for stream writing");
20
+ let isJson = false;
21
+ let replacer;
22
+ let spaces;
23
+ let encoding;
24
+ let mode;
25
+ let flag;
26
+ if (options) {
27
+ isJson = options.isJson ?? isJson;
28
+ replacer = options.replacer;
29
+ spaces = options.spaces;
30
+ encoding = options.encoding;
31
+ mode = options.mode ? Number(options.mode) : void 0;
32
+ flag = options.flag;
33
+ }
34
+ let stringData;
35
+ if (typeof data === "string") {
36
+ stringData = data;
37
+ } else if (data instanceof Uint8Array) {
38
+ stringData = Buffer.from(data).toString(encoding || "utf8");
39
+ } else if (data instanceof Blob || data instanceof Response) {
40
+ throw new Error("Blob and Response are not supported in sync context");
41
+ } else if (data instanceof ArrayBuffer) {
42
+ stringData = Buffer.from(new Uint8Array(data)).toString(encoding || "utf8");
43
+ } else if (ArrayBuffer.isView(data)) {
44
+ stringData = Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(encoding || "utf8");
45
+ } else if (isJson) {
46
+ try {
47
+ stringData = JSON.stringify(data, replacer, spaces);
48
+ if (stringData === void 0) {
49
+ throw new Error("Failed to stringify JSON object");
50
+ }
51
+ } catch (err) {
52
+ throw new Error(`Failed to stringify JSON data: ${err}`);
33
53
  }
54
+ } else {
55
+ stringData = String(data);
56
+ }
57
+ if (isStdStream(file)) {
58
+ file.write(stringData);
34
59
  return;
35
60
  }
36
61
  if (isFileDescriptor(file)) {
37
62
  if (isBun) {
38
- let writeData;
39
- if (typeof data === "string") {
40
- writeData = data;
41
- } else if (data instanceof Uint8Array) {
42
- writeData = data;
43
- } else if (data instanceof Blob || data instanceof Response) {
44
- throw new Error("Blob and Response are not supported in sync context with Bun");
45
- } else if (data instanceof ArrayBuffer) {
46
- writeData = new Uint8Array(data);
47
- } else if (ArrayBuffer.isView(data)) {
48
- writeData = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
49
- } else {
50
- throw new Error("Unsupported data type for Bun file descriptor writing");
51
- }
52
- Bun.write(Bun.file(file), writeData);
63
+ Bun.write(Bun.file(file), stringData);
53
64
  return;
54
65
  }
55
- if (data instanceof Blob || data instanceof Response) {
56
- throw new Error("Blob and Response are not supported for file descriptors in sync context");
57
- }
58
- nodeWriteFileSync(file, data, options);
66
+ nodeWriteFileSync(file, stringData, { encoding: encoding || "utf8", mode, flag });
59
67
  return;
60
68
  }
61
69
  if (file instanceof URL) {
@@ -72,38 +80,12 @@ export function writeFileSync(file, data, options) {
72
80
  if (isBun) {
73
81
  try {
74
82
  const filePath = file.toString();
75
- let writeData;
76
- if (typeof data === "string") {
77
- writeData = data;
78
- } else if (data instanceof Uint8Array) {
79
- writeData = data;
80
- } else if (data instanceof Blob || data instanceof Response) {
81
- throw new Error("Blob and Response are not supported in sync context with Bun");
82
- } else if (data instanceof ArrayBuffer) {
83
- writeData = new Uint8Array(data);
84
- } else if (ArrayBuffer.isView(data)) {
85
- writeData = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
86
- } else {
87
- throw new Error("Unsupported data type for Bun file writing");
88
- }
89
- Bun.write(filePath, writeData);
83
+ Bun.write(filePath, stringData);
90
84
  return;
91
85
  } catch (_error) {
92
86
  }
93
87
  }
94
- let nodeData;
95
- if (data instanceof Blob || data instanceof Response) {
96
- throw new Error("Blob and Response are not supported in sync context");
97
- } else if (typeof data === "string") {
98
- nodeData = data;
99
- } else if (data instanceof ArrayBuffer) {
100
- nodeData = Buffer.from(new Uint8Array(data));
101
- } else if (ArrayBuffer.isView(data)) {
102
- nodeData = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
103
- } else {
104
- throw new Error("Unsupported data type for Node.js file writing");
105
- }
106
- nodeWriteFileSync(file, nodeData, options);
88
+ nodeWriteFileSync(file, stringData, { encoding: encoding || "utf8", mode, flag });
107
89
  }
108
90
  export async function writeFile(file, data, options) {
109
91
  let isJson = false;
@@ -122,56 +104,42 @@ export async function writeFile(file, data, options) {
122
104
  mode = options.mode ? Number(options.mode) : void 0;
123
105
  flag = options.flag;
124
106
  }
125
- if (isJson && typeof data !== "string" && !(data instanceof Uint8Array) && !(data instanceof Blob) && !(data instanceof Response)) {
107
+ let stringData;
108
+ if (typeof data === "string") {
109
+ stringData = data;
110
+ } else if (data instanceof Uint8Array) {
111
+ stringData = Buffer.from(data).toString(encoding || "utf8");
112
+ } else if (data instanceof Blob) {
113
+ stringData = await data.text();
114
+ } else if (data instanceof Response) {
115
+ stringData = await data.text();
116
+ } else if (data instanceof ArrayBuffer) {
117
+ stringData = Buffer.from(new Uint8Array(data)).toString(encoding || "utf8");
118
+ } else if (ArrayBuffer.isView(data)) {
119
+ stringData = Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(encoding || "utf8");
120
+ } else if (isJson) {
126
121
  try {
127
- const jsonString = JSON.stringify(data, replacer, spaces);
128
- if (jsonString === void 0) {
122
+ stringData = JSON.stringify(data, replacer, spaces);
123
+ if (stringData === void 0) {
129
124
  throw new Error("Failed to stringify JSON object");
130
125
  }
131
- data = jsonString;
132
126
  } catch (err) {
133
127
  throw new Error(`Failed to stringify JSON data: ${err}`);
134
128
  }
129
+ } else {
130
+ stringData = String(data);
135
131
  }
136
132
  if (isStdStream(file)) {
137
- if (typeof data === "string") {
138
- file.write(data);
139
- } else if (data instanceof Uint8Array) {
140
- file.write(data);
141
- } else if (data instanceof Blob || data instanceof Response) {
142
- throw new Error("Blob and Response are not supported for stdout/stderr in sync context");
143
- } else if (data instanceof ArrayBuffer) {
144
- file.write(Buffer.from(new Uint8Array(data)));
145
- } else if (ArrayBuffer.isView(data)) {
146
- file.write(Buffer.from(data.buffer, data.byteOffset, data.byteLength));
147
- } else {
148
- throw new Error("Unsupported data type for stream writing");
149
- }
133
+ file.write(stringData);
150
134
  return;
151
135
  }
152
136
  if (isFileDescriptor(file)) {
153
137
  if (isBun) {
154
- let writeData;
155
- if (typeof data === "string") {
156
- writeData = data;
157
- } else if (data instanceof Uint8Array) {
158
- writeData = data;
159
- } else if (data instanceof Blob || data instanceof Response) {
160
- throw new Error("Blob and Response are not supported in sync context with Bun");
161
- } else if (data instanceof ArrayBuffer) {
162
- writeData = new Uint8Array(data);
163
- } else if (ArrayBuffer.isView(data)) {
164
- writeData = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
165
- } else {
166
- throw new Error("Unsupported data type for Bun file descriptor writing");
167
- }
168
- Bun.write(Bun.file(file), writeData);
138
+ await Bun.write(Bun.file(file), stringData);
169
139
  return;
170
140
  }
171
- if (data instanceof Blob || data instanceof Response) {
172
- throw new Error("Blob and Response are not supported for file descriptors in sync context");
173
- }
174
- return nodeWriteFileSync(file, data, options);
141
+ await nodeWriteFileAsync(file, stringData, { encoding: encoding || "utf8", mode, flag });
142
+ return;
175
143
  }
176
144
  if (file instanceof URL) {
177
145
  if (file.protocol !== "file:") {
@@ -183,30 +151,16 @@ export async function writeFile(file, data, options) {
183
151
  throw new Error("Invalid file target");
184
152
  }
185
153
  const dir = path.dirname(file.toString());
186
- try {
187
- await stat(dir);
188
- } catch (_error) {
189
- if (_error.code === "ENOENT") {
190
- await mkdir(dir, { recursive: true });
191
- } else {
192
- throw _error;
193
- }
194
- }
195
- if (useStreaming && typeof data === "string") {
154
+ await mkdir(dir, { recursive: true });
155
+ if (useStreaming) {
196
156
  try {
197
- const writeStream = createWriteStream(file.toString(), {
198
- encoding,
199
- mode,
200
- flags: flag
201
- });
157
+ const writeStream = createWriteStream(file, { encoding: encoding || "utf8", mode, flags: flag });
202
158
  const transform = new Transform({
203
159
  transform(chunk, _encoding, callback) {
204
160
  callback(null, chunk);
205
161
  }
206
162
  });
207
- transform.write(data);
208
- transform.end();
209
- await pipeline(transform, writeStream);
163
+ await pipeline(stringData, transform, writeStream);
210
164
  return;
211
165
  } catch (streamError) {
212
166
  }
@@ -214,44 +168,10 @@ export async function writeFile(file, data, options) {
214
168
  if (isBun) {
215
169
  try {
216
170
  const filePath = file.toString();
217
- let writeData;
218
- if (typeof data === "string") {
219
- writeData = data;
220
- } else if (data instanceof Uint8Array) {
221
- writeData = data;
222
- } else if (data instanceof Blob) {
223
- const buffer = await data.arrayBuffer();
224
- writeData = new Uint8Array(buffer);
225
- } else if (data instanceof Response) {
226
- const buffer = await data.arrayBuffer();
227
- writeData = new Uint8Array(buffer);
228
- } else if (data instanceof ArrayBuffer) {
229
- writeData = new Uint8Array(data);
230
- } else if (ArrayBuffer.isView(data)) {
231
- writeData = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
232
- } else {
233
- throw new Error("Unsupported data type for Bun file writing");
234
- }
235
- await Bun.write(filePath, writeData);
171
+ await Bun.write(filePath, stringData);
236
172
  return;
237
173
  } catch (_error) {
238
174
  }
239
175
  }
240
- let nodeData;
241
- if (data instanceof Blob) {
242
- const buffer = await data.arrayBuffer();
243
- nodeData = Buffer.from(buffer);
244
- } else if (data instanceof Response) {
245
- const buffer = await data.arrayBuffer();
246
- nodeData = Buffer.from(buffer);
247
- } else if (typeof data === "string") {
248
- nodeData = data;
249
- } else if (data instanceof ArrayBuffer) {
250
- nodeData = Buffer.from(new Uint8Array(data));
251
- } else if (ArrayBuffer.isView(data)) {
252
- nodeData = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
253
- } else {
254
- throw new Error("Unsupported data type for Node.js file writing");
255
- }
256
- await nodeWriteFileAsync(file, nodeData, options);
176
+ await nodeWriteFileAsync(file, stringData, { encoding: encoding || "utf8", mode, flag });
257
177
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "license": "MIT",
6
6
  "name": "@reliverse/relifso",
7
7
  "type": "module",
8
- "version": "1.4.1",
8
+ "version": "1.4.2",
9
9
  "keywords": [
10
10
  "fs",
11
11
  "file",