@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.
- package/LICENSES +16 -0
- package/README.md +48 -17
- package/bin/impl/bun.d.ts +5 -28
- package/bin/impl/bun.js +2 -126
- package/bin/impl/copy.js +8 -7
- package/bin/impl/create.d.ts +34 -0
- package/bin/impl/create.js +54 -0
- package/bin/impl/dive.d.ts +10 -0
- package/bin/impl/dive.js +89 -0
- package/bin/impl/empty.d.ts +28 -0
- package/bin/impl/empty.js +75 -0
- package/bin/impl/extras.d.ts +22 -2
- package/bin/impl/extras.js +68 -3
- package/bin/impl/json-utils.d.ts +30 -0
- package/bin/impl/json-utils.js +46 -0
- package/bin/impl/output-file.d.ts +3 -2
- package/bin/impl/output-json.d.ts +7 -2
- package/bin/impl/output-json.js +73 -11
- package/bin/impl/read-file.d.ts +11 -0
- package/bin/impl/read-file.js +82 -4
- package/bin/impl/read-json.d.ts +6 -0
- package/bin/impl/read-json.js +133 -21
- package/bin/impl/stats.d.ts +31 -0
- package/bin/impl/stats.js +141 -0
- package/bin/impl/write-file.d.ts +19 -8
- package/bin/impl/write-file.js +218 -9
- package/bin/impl/write-json.d.ts +13 -2
- package/bin/impl/write-json.js +46 -7
- package/bin/mod.d.ts +84 -36
- package/bin/mod.js +108 -39
- package/bin/utils/json/helpers/JSONRepairError.d.ts +4 -0
- package/bin/utils/json/helpers/JSONRepairError.js +7 -0
- package/bin/utils/json/helpers/JsonSchemaError.d.ts +6 -0
- package/bin/utils/json/helpers/JsonSchemaError.js +6 -0
- package/bin/utils/json/helpers/stringUtils.d.ts +64 -0
- package/bin/utils/json/helpers/stringUtils.js +87 -0
- package/bin/utils/json/regular/jsonc.d.ts +45 -0
- package/bin/utils/json/regular/jsonc.js +88 -0
- package/bin/utils/json/regular/jsonrepair.d.ts +17 -0
- package/bin/utils/json/regular/jsonrepair.js +576 -0
- package/bin/utils/json/regular/validate.d.ts +22 -0
- package/bin/utils/json/regular/validate.js +52 -0
- package/bin/utils/json/stream/JsonStreamError.d.ts +6 -0
- package/bin/utils/json/stream/JsonStreamError.js +6 -0
- package/bin/utils/json/stream/buffer/InputBuffer.d.ts +13 -0
- package/bin/utils/json/stream/buffer/InputBuffer.js +68 -0
- package/bin/utils/json/stream/buffer/OutputBuffer.d.ts +17 -0
- package/bin/utils/json/stream/buffer/OutputBuffer.js +101 -0
- package/bin/utils/json/stream/core.d.ts +10 -0
- package/bin/utils/json/stream/core.js +695 -0
- package/bin/utils/json/stream/jsonl.d.ts +21 -0
- package/bin/utils/json/stream/jsonl.js +55 -0
- package/bin/utils/json/stream/parser.d.ts +14 -0
- package/bin/utils/json/stream/parser.js +81 -0
- package/bin/utils/json/stream/stack.d.ts +19 -0
- package/bin/utils/json/stream/stack.js +43 -0
- package/bin/utils/json/stream/stream.d.ts +6 -0
- package/bin/utils/json/stream/stream.js +30 -0
- package/bin/utils/json/stream/writer.d.ts +14 -0
- package/bin/utils/json/stream/writer.js +44 -0
- package/package.json +3 -2
- package/bin/impl/create-file.d.ts +0 -2
- package/bin/impl/create-file.js +0 -21
- package/bin/impl/dive-async.d.ts +0 -11
- package/bin/impl/dive-async.js +0 -88
- package/bin/impl/empty-dir.d.ts +0 -2
- package/bin/impl/empty-dir.js +0 -24
- package/bin/impl/file-utils.d.ts +0 -20
- package/bin/impl/file-utils.js +0 -63
- /package/bin/{impl/logger.d.ts → utils/log.d.ts} +0 -0
- /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
|
+
}
|
package/bin/impl/write-file.d.ts
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
|
-
import { type PathLike } from "node:fs";
|
|
2
|
-
|
|
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.
|
|
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:
|
|
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.
|
|
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:
|
|
30
|
+
export declare function writeFile(file: WriteTarget, data: string | NodeJS.ArrayBufferView | Blob | Response | unknown, options?: WriteFileOptions): Promise<void>;
|
|
31
|
+
export {};
|
package/bin/impl/write-file.js
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
+
throw new Error("Unsupported data type for Bun file writing");
|
|
41
234
|
}
|
|
42
|
-
await Bun.write(
|
|
235
|
+
await Bun.write(filePath, writeData);
|
|
43
236
|
return;
|
|
44
237
|
} catch (_error) {
|
|
45
238
|
}
|
|
46
239
|
}
|
|
47
|
-
|
|
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
|
}
|
package/bin/impl/write-json.d.ts
CHANGED
|
@@ -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?:
|
|
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.
|
package/bin/impl/write-json.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|