@reliverse/relifso 1.3.0 → 1.4.0
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 +67 -12
- package/bin/impl/bun.d.ts +34 -0
- package/bin/impl/bun.js +147 -0
- package/bin/impl/copy.d.ts +15 -3
- package/bin/impl/copy.js +194 -60
- package/bin/impl/dive-async.d.ts +11 -0
- package/bin/impl/dive-async.js +88 -0
- package/bin/impl/extras.d.ts +15 -0
- package/bin/impl/extras.js +47 -0
- package/bin/impl/file-utils.d.ts +20 -0
- package/bin/impl/file-utils.js +63 -0
- package/bin/impl/logger.d.ts +1 -0
- package/bin/impl/logger.js +7 -0
- package/bin/impl/mkdirs.js +10 -3
- package/bin/impl/move.d.ts +10 -0
- package/bin/impl/move.js +92 -45
- package/bin/impl/read-file.d.ts +5 -15
- package/bin/impl/read-file.js +57 -0
- package/bin/impl/read-json.d.ts +3 -0
- package/bin/impl/read-json.js +83 -4
- package/bin/impl/write-file.js +31 -6
- package/bin/impl/write-json.d.ts +12 -10
- package/bin/impl/write-json.js +92 -18
- package/bin/mod.d.ts +25 -35
- package/bin/mod.js +59 -143
- package/package.json +3 -62
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readdir as nodeReaddirInternal, stat as nodeStatInternal } from "node:fs/promises";
|
|
2
|
+
import { join as pathJoin } from "node:path";
|
|
3
|
+
import { isBun, getStatsBun } from "./bun.js";
|
|
4
|
+
async function* _diveWorker(currentPath, options, currentDepth) {
|
|
5
|
+
const maxDepth = options.depth ?? Number.POSITIVE_INFINITY;
|
|
6
|
+
if (currentDepth > maxDepth) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
let entries;
|
|
10
|
+
try {
|
|
11
|
+
entries = await nodeReaddirInternal(currentPath, { withFileTypes: true });
|
|
12
|
+
} catch (_err) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const entryPath = pathJoin(currentPath, entry.name);
|
|
17
|
+
if (!(options.all ?? false) && entry.name.startsWith(".")) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (options.ignore) {
|
|
21
|
+
if (Array.isArray(options.ignore) && options.ignore.some((pattern) => entry.name.includes(pattern))) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (options.ignore instanceof RegExp && options.ignore.test(entryPath)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let entryStat;
|
|
29
|
+
try {
|
|
30
|
+
if (isBun) {
|
|
31
|
+
try {
|
|
32
|
+
entryStat = await getStatsBun(entryPath);
|
|
33
|
+
} catch (_error) {
|
|
34
|
+
entryStat = await nodeStatInternal(entryPath);
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
entryStat = await nodeStatInternal(entryPath);
|
|
38
|
+
}
|
|
39
|
+
} catch (_err) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
if (options.directories ?? false) {
|
|
44
|
+
yield { file: entryPath, stat: entryStat };
|
|
45
|
+
}
|
|
46
|
+
if (options.recursive ?? true) {
|
|
47
|
+
if (currentDepth < maxDepth) {
|
|
48
|
+
yield* _diveWorker(entryPath, options, currentDepth + 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else if (entry.isFile()) {
|
|
52
|
+
if (options.files ?? true) {
|
|
53
|
+
yield { file: entryPath, stat: entryStat };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function dive(directory, actionOrOptions, optionsOnly) {
|
|
59
|
+
let action;
|
|
60
|
+
let options;
|
|
61
|
+
if (typeof actionOrOptions === "function") {
|
|
62
|
+
action = actionOrOptions;
|
|
63
|
+
options = optionsOnly;
|
|
64
|
+
} else {
|
|
65
|
+
options = actionOrOptions;
|
|
66
|
+
}
|
|
67
|
+
const currentOptions = {
|
|
68
|
+
recursive: true,
|
|
69
|
+
files: true,
|
|
70
|
+
directories: false,
|
|
71
|
+
all: false,
|
|
72
|
+
depth: Number.POSITIVE_INFINITY,
|
|
73
|
+
...options
|
|
74
|
+
// User options override defaults
|
|
75
|
+
};
|
|
76
|
+
if (action) {
|
|
77
|
+
for await (const { file, stat: entryStat } of _diveWorker(directory, currentOptions, 0)) {
|
|
78
|
+
await action(file, entryStat);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
} else {
|
|
82
|
+
const results = [];
|
|
83
|
+
for await (const { file } of _diveWorker(directory, currentOptions, 0)) {
|
|
84
|
+
results.push(file);
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
export declare const execAsync: typeof exec.__promisify__;
|
|
3
|
+
export declare function setHiddenAttributeOnWindows(folderPath: string): Promise<void>;
|
|
4
|
+
export declare function isHidden(filePath: string): Promise<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a directory is empty
|
|
7
|
+
* @param directory Path to the directory
|
|
8
|
+
* @returns Boolean indicating if the directory is empty
|
|
9
|
+
*/
|
|
10
|
+
export declare function isDirectoryEmpty(directory: string): Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Removes the specified directory if it exists and then ensures it exists.
|
|
13
|
+
* @param dir - The directory to remove and ensure.
|
|
14
|
+
*/
|
|
15
|
+
export declare function rmEnsureDir(dir: string): Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ensuredir } from "@reliverse/relifso";
|
|
2
|
+
import { exec } from "node:child_process";
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { pathExists } from "./path-exists.js";
|
|
6
|
+
import { remove } from "./remove.js";
|
|
7
|
+
export const execAsync = promisify(exec);
|
|
8
|
+
export async function setHiddenAttributeOnWindows(folderPath) {
|
|
9
|
+
if (process.platform === "win32") {
|
|
10
|
+
try {
|
|
11
|
+
if (await pathExists(folderPath)) {
|
|
12
|
+
const isAlreadyHidden = await isHidden(folderPath);
|
|
13
|
+
if (!isAlreadyHidden) {
|
|
14
|
+
await execAsync(`attrib +h "${folderPath}"`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.warn("Failed to set hidden attribute:", String(error));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function isHidden(filePath) {
|
|
23
|
+
if (process.platform === "win32") {
|
|
24
|
+
const attributes = await execAsync(`attrib "${filePath}"`);
|
|
25
|
+
return attributes.stdout.includes("H");
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
export async function isDirectoryEmpty(directory) {
|
|
30
|
+
try {
|
|
31
|
+
const files = await readdir(directory);
|
|
32
|
+
return files.length === 0;
|
|
33
|
+
} catch (_error) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export async function rmEnsureDir(dir) {
|
|
38
|
+
try {
|
|
39
|
+
if (await pathExists(dir)) {
|
|
40
|
+
await remove(dir);
|
|
41
|
+
}
|
|
42
|
+
await ensuredir(dir);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(`Error while removing/ensuring directory ${dir}: ${error}`);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function readText(filePath: string, options?: BufferEncoding | {
|
|
2
|
+
encoding?: BufferEncoding | null;
|
|
3
|
+
flag?: string;
|
|
4
|
+
}): Promise<string | Buffer<ArrayBufferLike>>;
|
|
5
|
+
export declare function readTextSync(filePath: string, options?: BufferEncoding | {
|
|
6
|
+
encoding?: BufferEncoding | null;
|
|
7
|
+
flag?: string;
|
|
8
|
+
}): string | Buffer<ArrayBufferLike>;
|
|
9
|
+
export declare function readLines(filePath: string, options?: BufferEncoding | {
|
|
10
|
+
encoding?: BufferEncoding | null;
|
|
11
|
+
flag?: string;
|
|
12
|
+
}): Promise<string[]>;
|
|
13
|
+
export declare function readLinesSync(filePath: string, options?: BufferEncoding | {
|
|
14
|
+
encoding?: BufferEncoding | null;
|
|
15
|
+
flag?: string;
|
|
16
|
+
}): string[];
|
|
17
|
+
export declare function isDirectory(filePath: string): Promise<boolean>;
|
|
18
|
+
export declare function isDirectorySync(filePath: string): boolean;
|
|
19
|
+
export declare function isSymlink(filePath: string): Promise<boolean>;
|
|
20
|
+
export declare function isSymlinkSync(filePath: string): boolean;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { statSync, lstatSync } from "node:fs";
|
|
2
|
+
import { stat, lstat } from "node:fs/promises";
|
|
3
|
+
import { readFile, readFileSync } from "./read-file.js";
|
|
4
|
+
export async function readText(filePath, options = "utf8") {
|
|
5
|
+
return readFile(filePath, options);
|
|
6
|
+
}
|
|
7
|
+
export function readTextSync(filePath, options = "utf8") {
|
|
8
|
+
return readFileSync(filePath, options);
|
|
9
|
+
}
|
|
10
|
+
export async function readLines(filePath, options = { encoding: "utf8" }) {
|
|
11
|
+
const effectiveOptions = typeof options === "string" ? { encoding: options } : options;
|
|
12
|
+
const contentBuffer = await readFile(filePath, { ...effectiveOptions, encoding: null });
|
|
13
|
+
return contentBuffer.toString().split(/\r?\n/);
|
|
14
|
+
}
|
|
15
|
+
export function readLinesSync(filePath, options = { encoding: "utf8" }) {
|
|
16
|
+
const effectiveOptions = typeof options === "string" ? { encoding: options } : options;
|
|
17
|
+
const contentBuffer = readFileSync(filePath, { ...effectiveOptions, encoding: null });
|
|
18
|
+
return contentBuffer.toString().split(/\r?\n/);
|
|
19
|
+
}
|
|
20
|
+
export async function isDirectory(filePath) {
|
|
21
|
+
try {
|
|
22
|
+
const stats = await stat(filePath);
|
|
23
|
+
return stats.isDirectory();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function isDirectorySync(filePath) {
|
|
32
|
+
try {
|
|
33
|
+
const stats = statSync(filePath);
|
|
34
|
+
return stats.isDirectory();
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function isSymlink(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
const stats = await lstat(filePath);
|
|
45
|
+
return stats.isSymbolicLink();
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error.code === "ENOENT") {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function isSymlinkSync(filePath) {
|
|
54
|
+
try {
|
|
55
|
+
const stats = lstatSync(filePath);
|
|
56
|
+
return stats.isSymbolicLink();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (error.code === "ENOENT") {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const logInternal: (msg: string | (() => string)) => void;
|
package/bin/impl/mkdirs.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { mkdirSync, existsSync } from "node:fs";
|
|
2
2
|
import { mkdir, stat } from "node:fs/promises";
|
|
3
3
|
export function mkdirsSync(dir, options) {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (existsSync(dir)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
return mkdirSync(dir, { recursive: true, mode: options?.mode });
|
|
9
|
+
} catch (error) {
|
|
10
|
+
if (error.code === "EEXIST") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
throw error;
|
|
6
14
|
}
|
|
7
|
-
return mkdirSync(dir, { recursive: true, mode: options?.mode });
|
|
8
15
|
}
|
|
9
16
|
export async function mkdirs(dir, options) {
|
|
10
17
|
try {
|
package/bin/impl/move.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ export interface MoveOptions {
|
|
|
2
2
|
overwrite?: boolean;
|
|
3
3
|
/** @deprecated Use `overwrite`. */
|
|
4
4
|
clobber?: boolean;
|
|
5
|
+
/** Maximum number of retries for EBUSY errors (default: 3) */
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
/** Delay between retries in milliseconds (default: 100) */
|
|
8
|
+
retryDelay?: number;
|
|
9
|
+
/** Whether to ensure source exists before moving (default: true) */
|
|
10
|
+
ensureSource?: boolean;
|
|
11
|
+
/** Whether to ensure destination directory exists (default: true) */
|
|
12
|
+
ensureDest?: boolean;
|
|
13
|
+
/** Whether to verify operation success (default: true) */
|
|
14
|
+
verify?: boolean;
|
|
5
15
|
}
|
|
6
16
|
/**
|
|
7
17
|
* Moves a file or directory. If the destination is a directory, the source is moved into it.
|
package/bin/impl/move.js
CHANGED
|
@@ -3,20 +3,22 @@ import { rename, stat, unlink, copyFile } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, basename, join as joinPath } from "node:path";
|
|
4
4
|
import { mkdirsSync } from "./mkdirs.js";
|
|
5
5
|
import { mkdirs } from "./mkdirs.js";
|
|
6
|
+
import { pathExists, pathExistsSync } from "./path-exists.js";
|
|
6
7
|
export function moveSync(src, dest, options = {}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
const {
|
|
9
|
+
overwrite = options.clobber ?? false,
|
|
10
|
+
maxRetries = 3,
|
|
11
|
+
retryDelay = 100,
|
|
12
|
+
ensureSource = true,
|
|
13
|
+
ensureDest = true,
|
|
14
|
+
verify = true
|
|
15
|
+
} = options;
|
|
16
|
+
if (ensureSource && !pathExistsSync(src)) {
|
|
17
|
+
throw new Error(`Source ${src} does not exist.`);
|
|
17
18
|
}
|
|
18
|
-
const srcStat = statSync(src, { throwIfNoEntry:
|
|
19
|
+
const srcStat = statSync(src, { throwIfNoEntry: false });
|
|
19
20
|
if (!srcStat) {
|
|
21
|
+
throw new Error(`Source ${src} does not exist.`);
|
|
20
22
|
}
|
|
21
23
|
let destFinal = dest;
|
|
22
24
|
const destStat = statSync(dest, { throwIfNoEntry: false });
|
|
@@ -26,39 +28,63 @@ export function moveSync(src, dest, options = {}) {
|
|
|
26
28
|
if (statSync(destFinal, { throwIfNoEntry: false }) && !overwrite) {
|
|
27
29
|
throw new Error(`Destination ${destFinal} already exists and overwrite is false.`);
|
|
28
30
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
if (ensureDest) {
|
|
32
|
+
const destDir = dirname(destFinal);
|
|
33
|
+
mkdirsSync(destDir);
|
|
34
|
+
}
|
|
35
|
+
let lastError = null;
|
|
36
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
37
|
+
try {
|
|
38
|
+
renameSync(src, destFinal);
|
|
39
|
+
if (verify && !pathExistsSync(destFinal)) {
|
|
40
|
+
throw new Error(`Move operation failed: destination ${destFinal} does not exist after move`);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
lastError = err;
|
|
45
|
+
if (err.code === "EXDEV") {
|
|
46
|
+
copyFileSync(src, destFinal);
|
|
47
|
+
unlinkSync(src);
|
|
48
|
+
if (verify && !pathExistsSync(destFinal)) {
|
|
49
|
+
throw new Error(`Copy and unlink operation failed: destination ${destFinal} does not exist after operation`);
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
} else if (err.code === "EISDIR" || err.code === "EPERM") {
|
|
53
|
+
copyFileSync(src, destFinal);
|
|
54
|
+
unlinkSync(src);
|
|
55
|
+
if (verify && !pathExistsSync(destFinal)) {
|
|
56
|
+
throw new Error(`Copy and unlink operation failed: destination ${destFinal} does not exist after operation`);
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
} else if (err.code === "EBUSY" && attempt < maxRetries - 1) {
|
|
60
|
+
const start = Date.now();
|
|
61
|
+
while (Date.now() - start < retryDelay) {
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
41
65
|
throw err;
|
|
42
66
|
}
|
|
43
67
|
}
|
|
68
|
+
throw lastError;
|
|
44
69
|
}
|
|
45
70
|
export async function move(src, dest, options = {}) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
const {
|
|
72
|
+
overwrite = options.clobber ?? false,
|
|
73
|
+
maxRetries = 3,
|
|
74
|
+
retryDelay = 100,
|
|
75
|
+
ensureSource = true,
|
|
76
|
+
ensureDest = true,
|
|
77
|
+
verify = true
|
|
78
|
+
} = options;
|
|
79
|
+
if (ensureSource && !await pathExists(src)) {
|
|
80
|
+
throw new Error(`Source ${src} does not exist.`);
|
|
56
81
|
}
|
|
57
82
|
const srcStat = await stat(src).catch((e) => {
|
|
58
83
|
if (e.code === "ENOENT") return null;
|
|
59
84
|
throw e;
|
|
60
85
|
});
|
|
61
86
|
if (!srcStat) {
|
|
87
|
+
throw new Error(`Source ${src} does not exist.`);
|
|
62
88
|
}
|
|
63
89
|
let destFinal = dest;
|
|
64
90
|
const destStat = await stat(dest).catch((e) => {
|
|
@@ -75,19 +101,40 @@ export async function move(src, dest, options = {}) {
|
|
|
75
101
|
if (destFinalStat && !overwrite) {
|
|
76
102
|
throw new Error(`Destination ${destFinal} already exists and overwrite is false.`);
|
|
77
103
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
await
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
if (ensureDest) {
|
|
105
|
+
const destDir = dirname(destFinal);
|
|
106
|
+
await mkdirs(destDir);
|
|
107
|
+
}
|
|
108
|
+
let lastError = null;
|
|
109
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
110
|
+
try {
|
|
111
|
+
await rename(src, destFinal);
|
|
112
|
+
if (verify && !await pathExists(destFinal)) {
|
|
113
|
+
throw new Error(`Move operation failed: destination ${destFinal} does not exist after move`);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
} catch (err) {
|
|
117
|
+
lastError = err;
|
|
118
|
+
if (err.code === "EXDEV") {
|
|
119
|
+
await copyFile(src, destFinal);
|
|
120
|
+
await unlink(src);
|
|
121
|
+
if (verify && !await pathExists(destFinal)) {
|
|
122
|
+
throw new Error(`Copy and unlink operation failed: destination ${destFinal} does not exist after operation`);
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
} else if (err.code === "EISDIR" || err.code === "EPERM") {
|
|
126
|
+
await copyFile(src, destFinal);
|
|
127
|
+
await unlink(src);
|
|
128
|
+
if (verify && !await pathExists(destFinal)) {
|
|
129
|
+
throw new Error(`Copy and unlink operation failed: destination ${destFinal} does not exist after operation`);
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
} else if (err.code === "EBUSY" && attempt < maxRetries - 1) {
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
90
136
|
throw err;
|
|
91
137
|
}
|
|
92
138
|
}
|
|
139
|
+
throw lastError;
|
|
93
140
|
}
|
package/bin/impl/read-file.d.ts
CHANGED
|
@@ -3,28 +3,18 @@ export interface ReadFileOptions {
|
|
|
3
3
|
flag?: string;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Synchronously reads the entire contents of a file.
|
|
7
7
|
*
|
|
8
8
|
* @param path - The path to the file.
|
|
9
9
|
* @param options - Options for reading the file. Can be an encoding string or an object.
|
|
10
|
-
* @returns The
|
|
10
|
+
* @returns The contents of the file.
|
|
11
11
|
*/
|
|
12
|
-
export declare function readFileSync(path: string, options
|
|
13
|
-
encoding: BufferEncoding;
|
|
14
|
-
})): string;
|
|
15
|
-
export declare function readFileSync(path: string, options?: (ReadFileOptions & {
|
|
16
|
-
encoding?: null;
|
|
17
|
-
}) | null): Buffer;
|
|
12
|
+
export declare function readFileSync(path: string, options?: BufferEncoding | ReadFileOptions): string | Buffer;
|
|
18
13
|
/**
|
|
19
14
|
* Asynchronously reads the entire contents of a file.
|
|
20
15
|
*
|
|
21
16
|
* @param path - The path to the file.
|
|
22
17
|
* @param options - Options for reading the file. Can be an encoding string or an object.
|
|
23
|
-
* @returns A promise that resolves with the
|
|
18
|
+
* @returns A promise that resolves with the contents of the file.
|
|
24
19
|
*/
|
|
25
|
-
export declare function readFile(path: string, options
|
|
26
|
-
encoding: BufferEncoding;
|
|
27
|
-
})): Promise<string>;
|
|
28
|
-
export declare function readFile(path: string, options?: (ReadFileOptions & {
|
|
29
|
-
encoding?: null;
|
|
30
|
-
}) | null): Promise<Buffer>;
|
|
20
|
+
export declare function readFile(path: string, options?: BufferEncoding | ReadFileOptions): Promise<string | Buffer>;
|
package/bin/impl/read-file.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { readFileSync as nodeReadFileSync } from "node:fs";
|
|
2
2
|
import { readFile as nodeReadFileAsync } from "node:fs/promises";
|
|
3
|
+
import { isBun, getFileBun } from "./bun.js";
|
|
4
|
+
import { logInternal } from "./logger.js";
|
|
3
5
|
export function readFileSync(path, options) {
|
|
4
6
|
let encoding;
|
|
5
7
|
let flag;
|
|
@@ -9,6 +11,40 @@ export function readFileSync(path, options) {
|
|
|
9
11
|
encoding = options.encoding;
|
|
10
12
|
flag = options.flag;
|
|
11
13
|
}
|
|
14
|
+
if (isBun) {
|
|
15
|
+
try {
|
|
16
|
+
const file = getFileBun(path);
|
|
17
|
+
if (encoding) {
|
|
18
|
+
try {
|
|
19
|
+
const text = file.text();
|
|
20
|
+
if (text instanceof Promise) {
|
|
21
|
+
throw new Error("Bun's text() returned a Promise in sync context");
|
|
22
|
+
}
|
|
23
|
+
return text;
|
|
24
|
+
} catch (_error) {
|
|
25
|
+
const buffer = file.arrayBuffer();
|
|
26
|
+
if (buffer instanceof Promise) {
|
|
27
|
+
throw new Error("Bun's arrayBuffer() returned a Promise in sync context");
|
|
28
|
+
}
|
|
29
|
+
return Buffer.from(buffer).toString(encoding);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const buffer = file.arrayBuffer();
|
|
34
|
+
if (buffer instanceof Promise) {
|
|
35
|
+
throw new Error("Bun's arrayBuffer() returned a Promise in sync context");
|
|
36
|
+
}
|
|
37
|
+
return Buffer.from(buffer);
|
|
38
|
+
} catch (_error) {
|
|
39
|
+
const text = file.text();
|
|
40
|
+
if (text instanceof Promise) {
|
|
41
|
+
throw new Error("Bun's text() returned a Promise in sync context");
|
|
42
|
+
}
|
|
43
|
+
return Buffer.from(text);
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
12
48
|
if (encoding) {
|
|
13
49
|
return nodeReadFileSync(path, { encoding, flag });
|
|
14
50
|
}
|
|
@@ -23,6 +59,27 @@ export async function readFile(path, options) {
|
|
|
23
59
|
encoding = options.encoding;
|
|
24
60
|
flag = options.flag;
|
|
25
61
|
}
|
|
62
|
+
if (isBun) {
|
|
63
|
+
try {
|
|
64
|
+
const file = getFileBun(path);
|
|
65
|
+
if (encoding) {
|
|
66
|
+
try {
|
|
67
|
+
return await file.text();
|
|
68
|
+
} catch (_error) {
|
|
69
|
+
const buffer = await file.arrayBuffer();
|
|
70
|
+
return Buffer.from(buffer).toString(encoding);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const buffer = await file.arrayBuffer();
|
|
75
|
+
return Buffer.from(buffer);
|
|
76
|
+
} catch (_error) {
|
|
77
|
+
const text = await file.text();
|
|
78
|
+
return Buffer.from(text);
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
26
83
|
if (encoding) {
|
|
27
84
|
return nodeReadFileAsync(path, { encoding, flag });
|
|
28
85
|
}
|
package/bin/impl/read-json.d.ts
CHANGED
|
@@ -3,9 +3,12 @@ export interface ReadJsonOptions {
|
|
|
3
3
|
flag?: string;
|
|
4
4
|
reviver?: (key: string, value: unknown) => unknown;
|
|
5
5
|
throws?: boolean;
|
|
6
|
+
defaultValue?: unknown;
|
|
7
|
+
ensure?: boolean;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* Reads a JSON file and then parses it into an object.
|
|
11
|
+
* If the file doesn't exist and ensure is true, creates the file with defaultValue.
|
|
9
12
|
*
|
|
10
13
|
* @param file - The path to the file.
|
|
11
14
|
* @param options - Options for reading the file or parsing JSON. Can be an encoding string or an object.
|