@reliverse/relifso 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSES +16 -0
  2. package/README.md +48 -17
  3. package/bin/impl/bun.d.ts +5 -28
  4. package/bin/impl/bun.js +2 -126
  5. package/bin/impl/copy.js +8 -7
  6. package/bin/impl/create.d.ts +34 -0
  7. package/bin/impl/create.js +54 -0
  8. package/bin/impl/dive.d.ts +10 -0
  9. package/bin/impl/dive.js +89 -0
  10. package/bin/impl/empty.d.ts +28 -0
  11. package/bin/impl/empty.js +75 -0
  12. package/bin/impl/extras.d.ts +22 -2
  13. package/bin/impl/extras.js +68 -3
  14. package/bin/impl/json-utils.d.ts +30 -0
  15. package/bin/impl/json-utils.js +46 -0
  16. package/bin/impl/output-file.d.ts +3 -2
  17. package/bin/impl/output-json.d.ts +7 -2
  18. package/bin/impl/output-json.js +73 -11
  19. package/bin/impl/read-file.d.ts +11 -0
  20. package/bin/impl/read-file.js +82 -4
  21. package/bin/impl/read-json.d.ts +6 -0
  22. package/bin/impl/read-json.js +133 -21
  23. package/bin/impl/stats.d.ts +31 -0
  24. package/bin/impl/stats.js +141 -0
  25. package/bin/impl/write-file.d.ts +19 -8
  26. package/bin/impl/write-file.js +218 -9
  27. package/bin/impl/write-json.d.ts +13 -2
  28. package/bin/impl/write-json.js +46 -7
  29. package/bin/mod.d.ts +84 -36
  30. package/bin/mod.js +108 -39
  31. package/bin/utils/json/helpers/JSONRepairError.d.ts +4 -0
  32. package/bin/utils/json/helpers/JSONRepairError.js +7 -0
  33. package/bin/utils/json/helpers/JsonSchemaError.d.ts +6 -0
  34. package/bin/utils/json/helpers/JsonSchemaError.js +6 -0
  35. package/bin/utils/json/helpers/stringUtils.d.ts +64 -0
  36. package/bin/utils/json/helpers/stringUtils.js +87 -0
  37. package/bin/utils/json/regular/jsonc.d.ts +45 -0
  38. package/bin/utils/json/regular/jsonc.js +88 -0
  39. package/bin/utils/json/regular/jsonrepair.d.ts +17 -0
  40. package/bin/utils/json/regular/jsonrepair.js +576 -0
  41. package/bin/utils/json/regular/validate.d.ts +22 -0
  42. package/bin/utils/json/regular/validate.js +52 -0
  43. package/bin/utils/json/stream/JsonStreamError.d.ts +6 -0
  44. package/bin/utils/json/stream/JsonStreamError.js +6 -0
  45. package/bin/utils/json/stream/buffer/InputBuffer.d.ts +13 -0
  46. package/bin/utils/json/stream/buffer/InputBuffer.js +68 -0
  47. package/bin/utils/json/stream/buffer/OutputBuffer.d.ts +17 -0
  48. package/bin/utils/json/stream/buffer/OutputBuffer.js +101 -0
  49. package/bin/utils/json/stream/core.d.ts +10 -0
  50. package/bin/utils/json/stream/core.js +695 -0
  51. package/bin/utils/json/stream/jsonl.d.ts +21 -0
  52. package/bin/utils/json/stream/jsonl.js +55 -0
  53. package/bin/utils/json/stream/parser.d.ts +14 -0
  54. package/bin/utils/json/stream/parser.js +81 -0
  55. package/bin/utils/json/stream/stack.d.ts +19 -0
  56. package/bin/utils/json/stream/stack.js +43 -0
  57. package/bin/utils/json/stream/stream.d.ts +6 -0
  58. package/bin/utils/json/stream/stream.js +30 -0
  59. package/bin/utils/json/stream/writer.d.ts +14 -0
  60. package/bin/utils/json/stream/writer.js +44 -0
  61. package/package.json +3 -2
  62. package/bin/impl/create-file.d.ts +0 -2
  63. package/bin/impl/create-file.js +0 -21
  64. package/bin/impl/dive-async.d.ts +0 -11
  65. package/bin/impl/dive-async.js +0 -88
  66. package/bin/impl/empty-dir.d.ts +0 -2
  67. package/bin/impl/empty-dir.js +0 -24
  68. package/bin/impl/file-utils.d.ts +0 -20
  69. package/bin/impl/file-utils.js +0 -63
  70. /package/bin/{impl/logger.d.ts → utils/log.d.ts} +0 -0
  71. /package/bin/{impl/logger.js → utils/log.js} +0 -0
@@ -0,0 +1,31 @@
1
+ import type { Stats } from "node:fs";
2
+ /**
3
+ * Convert Bun file stats to Node.js Stats object
4
+ * Uses Bun's optimized API when available, falls back to Node.js
5
+ */
6
+ export declare function toNodeStats(path: string): Promise<Stats>;
7
+ /**
8
+ * Get file stats with fallback to Node.js
9
+ * Uses Bun's optimized API when available
10
+ */
11
+ export declare function getStats(path: string): Promise<Stats>;
12
+ /**
13
+ * Get file stats synchronously with fallback to Node.js
14
+ * Uses Bun's optimized API when available
15
+ */
16
+ export declare function getStatsSync(path: string): Stats;
17
+ /**
18
+ * Check if a file exists
19
+ * Uses Bun's optimized API when available, falls back to Node.js
20
+ */
21
+ export declare function getFileExists(path: string): Promise<boolean>;
22
+ /**
23
+ * Get file size
24
+ * Uses Bun's optimized API when available, falls back to Node.js
25
+ */
26
+ export declare function getFileSize(path: string): Promise<number>;
27
+ /**
28
+ * Get file last modified time
29
+ * Uses Bun's optimized API when available, falls back to Node.js
30
+ */
31
+ export declare function getFileLastModified(path: string): Promise<Date>;
@@ -0,0 +1,141 @@
1
+ import { statSync } from "node:fs";
2
+ import { stat } from "node:fs/promises";
3
+ import { logInternal } from "../utils/log.js";
4
+ import { isBun } from "./bun.js";
5
+ export async function toNodeStats(path) {
6
+ if (!isBun) {
7
+ return stat(path);
8
+ }
9
+ try {
10
+ const file = Bun.file(path);
11
+ const size = file.size;
12
+ const lastModified = new Date(file.lastModified);
13
+ return {
14
+ dev: 0,
15
+ ino: 0,
16
+ mode: 0,
17
+ nlink: 0,
18
+ uid: 0,
19
+ gid: 0,
20
+ rdev: 0,
21
+ size,
22
+ blksize: 0,
23
+ blocks: 0,
24
+ atimeMs: lastModified.getTime(),
25
+ mtimeMs: lastModified.getTime(),
26
+ ctimeMs: lastModified.getTime(),
27
+ birthtimeMs: lastModified.getTime(),
28
+ atime: lastModified,
29
+ mtime: lastModified,
30
+ ctime: lastModified,
31
+ birthtime: lastModified,
32
+ isDirectory: () => false,
33
+ // Bun doesn't provide this info directly
34
+ isFile: () => true,
35
+ isBlockDevice: () => false,
36
+ isCharacterDevice: () => false,
37
+ isSymbolicLink: () => false,
38
+ isFIFO: () => false,
39
+ isSocket: () => false
40
+ };
41
+ } catch (error) {
42
+ return stat(path);
43
+ }
44
+ }
45
+ export async function getStats(path) {
46
+ if (!isBun) {
47
+ return stat(path);
48
+ }
49
+ try {
50
+ return await toNodeStats(path);
51
+ } catch (error) {
52
+ return stat(path);
53
+ }
54
+ }
55
+ export function getStatsSync(path) {
56
+ if (!isBun) {
57
+ return statSync(path);
58
+ }
59
+ try {
60
+ const file = Bun.file(path);
61
+ const size = file.size;
62
+ const lastModified = new Date(file.lastModified);
63
+ return {
64
+ dev: 0,
65
+ ino: 0,
66
+ mode: 0,
67
+ nlink: 0,
68
+ uid: 0,
69
+ gid: 0,
70
+ rdev: 0,
71
+ size,
72
+ blksize: 0,
73
+ blocks: 0,
74
+ atimeMs: lastModified.getTime(),
75
+ mtimeMs: lastModified.getTime(),
76
+ ctimeMs: lastModified.getTime(),
77
+ birthtimeMs: lastModified.getTime(),
78
+ atime: lastModified,
79
+ mtime: lastModified,
80
+ ctime: lastModified,
81
+ birthtime: lastModified,
82
+ isDirectory: () => false,
83
+ isFile: () => true,
84
+ isBlockDevice: () => false,
85
+ isCharacterDevice: () => false,
86
+ isSymbolicLink: () => false,
87
+ isFIFO: () => false,
88
+ isSocket: () => false
89
+ };
90
+ } catch (error) {
91
+ return statSync(path);
92
+ }
93
+ }
94
+ export async function getFileExists(path) {
95
+ if (!isBun) {
96
+ try {
97
+ await stat(path);
98
+ return true;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+ try {
104
+ const file = Bun.file(path);
105
+ return await file.exists();
106
+ } catch (error) {
107
+ return false;
108
+ }
109
+ }
110
+ export async function getFileSize(path) {
111
+ if (!isBun) {
112
+ try {
113
+ const stats = await stat(path);
114
+ return stats.size;
115
+ } catch (error) {
116
+ return 0;
117
+ }
118
+ }
119
+ try {
120
+ const file = Bun.file(path);
121
+ return file.size;
122
+ } catch (error) {
123
+ return 0;
124
+ }
125
+ }
126
+ export async function getFileLastModified(path) {
127
+ if (!isBun) {
128
+ try {
129
+ const stats = await stat(path);
130
+ return stats.mtime;
131
+ } catch (error) {
132
+ return /* @__PURE__ */ new Date(0);
133
+ }
134
+ }
135
+ try {
136
+ const file = Bun.file(path);
137
+ return new Date(file.lastModified);
138
+ } catch (error) {
139
+ return /* @__PURE__ */ new Date(0);
140
+ }
141
+ }
@@ -1,20 +1,31 @@
1
- import { type PathLike } from "node:fs";
2
- export type WriteFileOptions = import("node:fs").WriteFileOptions;
1
+ import { type PathLike, type WriteStream } from "node:fs";
2
+ import { URL } from "node:url";
3
+ export interface WriteFileOptions {
4
+ encoding?: BufferEncoding | null;
5
+ mode?: number;
6
+ flag?: string;
7
+ isJson?: boolean;
8
+ useStreaming?: boolean;
9
+ replacer?: (key: string, value: unknown) => unknown;
10
+ spaces?: string | number;
11
+ }
12
+ type WriteTarget = PathLike | number | URL | WriteStream;
3
13
  /**
4
14
  * Synchronously writes data to a file, replacing the file if it already exists.
5
15
  * Ensures the directory exists before writing.
6
16
  *
7
- * @param file - Path to the file.
8
- * @param data - The data to write. If something other than a Buffer or Uint8Array is provided, it is converted to a string.
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.
9
19
  * @param options - Options for writing the file. Can be an encoding string or an object.
10
20
  */
11
- export declare function writeFileSync(file: PathLike | number, data: string | NodeJS.ArrayBufferView, options?: WriteFileOptions): void;
21
+ export declare function writeFileSync(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response, options?: WriteFileOptions): void;
12
22
  /**
13
23
  * Asynchronously writes data to a file, replacing the file if it already exists.
14
24
  * Ensures the directory exists before writing.
15
25
  *
16
- * @param file - Path to the file.
17
- * @param data - The data to write. If something other than a Buffer or Uint8Array is provided, it is converted to a string.
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.
18
28
  * @param options - Options for writing the file. Can be an encoding string or an object.
19
29
  */
20
- export declare function writeFile(file: PathLike | number, data: string | NodeJS.ArrayBufferView, options?: WriteFileOptions): Promise<void>;
30
+ export declare function writeFile(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response | unknown, options?: WriteFileOptions): Promise<void>;
31
+ export {};
@@ -1,22 +1,187 @@
1
- import { writeFileSync as nodeWriteFileSync } from "node:fs";
1
+ import { writeFileSync as nodeWriteFileSync, createWriteStream } from "node:fs";
2
2
  import { mkdir, writeFile as nodeWriteFileAsync, stat } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { isBun, getFileBun } from "./bun.js";
5
- import { logInternal } from "./logger.js";
4
+ import { Transform } from "node:stream";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { URL } from "node:url";
7
+ import { logInternal } from "../utils/log.js";
8
+ import { isBun } from "./bun.js";
6
9
  import { mkdirsSync } from "./mkdirs.js";
10
+ function isStdStream(target) {
11
+ return typeof target === "object" && target !== null && "write" in target && typeof target.write === "function";
12
+ }
13
+ function isFileDescriptor(target) {
14
+ return typeof target === "number";
15
+ }
16
+ function isPathLike(target) {
17
+ return !isStdStream(target) && !isFileDescriptor(target) && !(target instanceof URL);
18
+ }
7
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");
33
+ }
34
+ return;
35
+ }
36
+ if (isFileDescriptor(file)) {
37
+ 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);
53
+ return;
54
+ }
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);
59
+ return;
60
+ }
61
+ if (file instanceof URL) {
62
+ if (file.protocol !== "file:") {
63
+ throw new Error("Only file:// URLs are supported");
64
+ }
65
+ file = file.pathname;
66
+ }
67
+ if (!isPathLike(file)) {
68
+ throw new Error("Invalid file target");
69
+ }
8
70
  const dir = path.dirname(file.toString());
9
71
  mkdirsSync(dir);
10
72
  if (isBun) {
11
73
  try {
12
- nodeWriteFileSync(file, data, options);
74
+ 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);
13
90
  return;
14
91
  } catch (_error) {
15
92
  }
16
93
  }
17
- nodeWriteFileSync(file, data, options);
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);
18
107
  }
19
108
  export async function writeFile(file, data, options) {
109
+ let isJson = false;
110
+ let useStreaming = false;
111
+ let replacer;
112
+ let spaces;
113
+ let encoding;
114
+ let mode;
115
+ let flag;
116
+ if (options) {
117
+ isJson = options.isJson ?? isJson;
118
+ useStreaming = options.useStreaming ?? useStreaming;
119
+ replacer = options.replacer;
120
+ spaces = options.spaces;
121
+ encoding = options.encoding;
122
+ mode = options.mode ? Number(options.mode) : void 0;
123
+ flag = options.flag;
124
+ }
125
+ if (isJson && typeof data !== "string" && !(data instanceof Uint8Array) && !(data instanceof Blob) && !(data instanceof Response)) {
126
+ try {
127
+ const jsonString = JSON.stringify(data, replacer, spaces);
128
+ if (jsonString === void 0) {
129
+ throw new Error("Failed to stringify JSON object");
130
+ }
131
+ data = jsonString;
132
+ } catch (err) {
133
+ throw new Error(`Failed to stringify JSON data: ${err}`);
134
+ }
135
+ }
136
+ 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
+ }
150
+ return;
151
+ }
152
+ if (isFileDescriptor(file)) {
153
+ 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);
169
+ return;
170
+ }
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);
175
+ }
176
+ if (file instanceof URL) {
177
+ if (file.protocol !== "file:") {
178
+ throw new Error("Only file:// URLs are supported");
179
+ }
180
+ file = file.pathname;
181
+ }
182
+ if (!isPathLike(file)) {
183
+ throw new Error("Invalid file target");
184
+ }
20
185
  const dir = path.dirname(file.toString());
21
186
  try {
22
187
  await stat(dir);
@@ -27,22 +192,66 @@ export async function writeFile(file, data, options) {
27
192
  throw _error;
28
193
  }
29
194
  }
195
+ if (useStreaming && typeof data === "string") {
196
+ try {
197
+ const writeStream = createWriteStream(file.toString(), {
198
+ encoding,
199
+ mode,
200
+ flags: flag
201
+ });
202
+ const transform = new Transform({
203
+ transform(chunk, _encoding, callback) {
204
+ callback(null, chunk);
205
+ }
206
+ });
207
+ transform.write(data);
208
+ transform.end();
209
+ await pipeline(transform, writeStream);
210
+ return;
211
+ } catch (streamError) {
212
+ }
213
+ }
30
214
  if (isBun) {
31
215
  try {
32
216
  const filePath = file.toString();
33
- const bunFile = getFileBun(filePath);
34
217
  let writeData;
35
218
  if (typeof data === "string") {
36
219
  writeData = data;
37
220
  } else if (data instanceof Uint8Array) {
38
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);
39
232
  } else {
40
- writeData = new Uint8Array(data.buffer);
233
+ throw new Error("Unsupported data type for Bun file writing");
41
234
  }
42
- await Bun.write(bunFile, writeData);
235
+ await Bun.write(filePath, writeData);
43
236
  return;
44
237
  } catch (_error) {
45
238
  }
46
239
  }
47
- return nodeWriteFileAsync(file, data, options);
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);
48
257
  }
@@ -1,15 +1,26 @@
1
- import type { Mode } from "node:fs";
2
1
  export interface JsonStringifyOptions {
3
2
  replacer?: (key: string, value: unknown) => unknown | (number | string)[] | null;
4
3
  spaces?: string | number;
4
+ /**
5
+ * Whether to include comments when writing JSONC files
6
+ * @default false
7
+ */
8
+ includeComments?: boolean;
5
9
  }
6
10
  export interface WriteJsonOptions {
7
11
  encoding?: BufferEncoding | null;
8
- mode?: Mode;
12
+ mode?: number;
9
13
  flag?: string;
10
14
  replacer?: (key: string, value: unknown) => unknown | (number | string)[] | null;
11
15
  spaces?: string | number;
12
16
  throws?: boolean;
17
+ useStreaming?: boolean;
18
+ chunkSize?: number;
19
+ /**
20
+ * Whether to include comments when writing JSONC files
21
+ * @default false
22
+ */
23
+ includeComments?: boolean;
13
24
  }
14
25
  /**
15
26
  * Synchronously writes a JSON file.
@@ -1,5 +1,10 @@
1
+ import { createWriteStream } from "node:fs";
2
+ import { extname } from "node:path";
3
+ import { Transform } from "node:stream";
4
+ import { pipeline } from "node:stream/promises";
5
+ import { stringifyJsonc } from "../utils/json/regular/jsonc.js";
6
+ import { logInternal } from "../utils/log.js";
1
7
  import { isBun, getFileBun } from "./bun.js";
2
- import { logInternal } from "./logger.js";
3
8
  import { writeFileSync } from "./write-file.js";
4
9
  import { writeFile } from "./write-file.js";
5
10
  export function writeJsonSync(file, object, options) {
@@ -9,6 +14,7 @@ export function writeJsonSync(file, object, options) {
9
14
  let flag;
10
15
  let mode;
11
16
  let throws = true;
17
+ let includeComments = false;
12
18
  if (typeof options === "string") {
13
19
  encoding = options;
14
20
  } else if (options) {
@@ -17,6 +23,7 @@ export function writeJsonSync(file, object, options) {
17
23
  spaces = options.spaces;
18
24
  flag = options.flag;
19
25
  mode = options.mode;
26
+ includeComments = options.includeComments ?? includeComments;
20
27
  if (options.throws !== void 0) {
21
28
  throws = options.throws;
22
29
  }
@@ -25,19 +32,19 @@ export function writeJsonSync(file, object, options) {
25
32
  if (object === void 0) {
26
33
  throw new Error("Cannot write undefined as JSON");
27
34
  }
35
+ const isJsonc = extname(file).toLowerCase() === ".jsonc";
28
36
  if (isBun) {
29
37
  try {
30
- const fileRef = getFileBun(file);
31
- const jsonString2 = JSON.stringify(object, replacer, spaces);
38
+ const jsonString2 = isJsonc ? stringifyJsonc(object, { includeComments, spaces: typeof spaces === "number" ? spaces : 2 }) : JSON.stringify(object, replacer, spaces);
32
39
  if (jsonString2 === void 0) {
33
40
  throw new Error("Failed to stringify JSON object");
34
41
  }
35
- Bun.write(fileRef, jsonString2);
42
+ writeFileSync(file, jsonString2, { encoding, flag, mode });
36
43
  return;
37
44
  } catch (error) {
38
45
  }
39
46
  }
40
- const jsonString = JSON.stringify(object, replacer, spaces);
47
+ const jsonString = isJsonc ? stringifyJsonc(object, { includeComments, spaces: typeof spaces === "number" ? spaces : 2 }) : JSON.stringify(object, replacer, spaces);
41
48
  if (jsonString === void 0) {
42
49
  throw new Error("Failed to stringify JSON object");
43
50
  }
@@ -55,6 +62,9 @@ export async function writeJson(file, object, options) {
55
62
  let flag;
56
63
  let mode;
57
64
  let throws = true;
65
+ let useStreaming = false;
66
+ let chunkSize = 1024 * 1024;
67
+ let includeComments = false;
58
68
  if (typeof options === "string") {
59
69
  encoding = options;
60
70
  } else if (options) {
@@ -63,6 +73,9 @@ export async function writeJson(file, object, options) {
63
73
  spaces = options.spaces;
64
74
  flag = options.flag;
65
75
  mode = options.mode;
76
+ useStreaming = options.useStreaming ?? useStreaming;
77
+ chunkSize = options.chunkSize ?? chunkSize;
78
+ includeComments = options.includeComments ?? includeComments;
66
79
  if (options.throws !== void 0) {
67
80
  throws = options.throws;
68
81
  }
@@ -71,10 +84,11 @@ export async function writeJson(file, object, options) {
71
84
  if (object === void 0) {
72
85
  throw new Error("Cannot write undefined as JSON");
73
86
  }
87
+ const isJsonc = extname(file).toLowerCase() === ".jsonc";
74
88
  if (isBun) {
75
89
  try {
76
90
  const fileRef = getFileBun(file);
77
- const jsonString2 = JSON.stringify(object, replacer, spaces);
91
+ const jsonString2 = isJsonc ? stringifyJsonc(object, { includeComments, spaces: typeof spaces === "number" ? spaces : 2 }) : JSON.stringify(object, replacer, spaces);
78
92
  if (jsonString2 === void 0) {
79
93
  throw new Error("Failed to stringify JSON object");
80
94
  }
@@ -83,7 +97,32 @@ export async function writeJson(file, object, options) {
83
97
  } catch (error) {
84
98
  }
85
99
  }
86
- const jsonString = JSON.stringify(object, replacer, spaces);
100
+ if (useStreaming) {
101
+ try {
102
+ const writeStream = createWriteStream(file, {
103
+ encoding,
104
+ mode: mode ? Number(mode) : void 0,
105
+ flags: flag,
106
+ highWaterMark: chunkSize
107
+ // Use chunkSize for stream buffer size
108
+ });
109
+ const jsonString2 = isJsonc ? stringifyJsonc(object, { includeComments, spaces: typeof spaces === "number" ? spaces : 2 }) : JSON.stringify(object, replacer, spaces);
110
+ if (jsonString2 === void 0) {
111
+ throw new Error("Failed to stringify JSON object");
112
+ }
113
+ const transform = new Transform({
114
+ transform(chunk, _encoding, callback) {
115
+ callback(null, chunk);
116
+ }
117
+ });
118
+ transform.write(jsonString2);
119
+ transform.end();
120
+ await pipeline(transform, writeStream);
121
+ return;
122
+ } catch (streamError) {
123
+ }
124
+ }
125
+ const jsonString = isJsonc ? stringifyJsonc(object, { includeComments, spaces: typeof spaces === "number" ? spaces : 2 }) : JSON.stringify(object, replacer, spaces);
87
126
  if (jsonString === void 0) {
88
127
  throw new Error("Failed to stringify JSON object");
89
128
  }