pwd-fs 3.3.5 → 3.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/dist/powered-file-system/copy.d.ts +3 -1
- package/dist/powered-file-system/copy.js +4 -3
- package/dist/powered-file-system/copy.test.js +46 -0
- package/dist/powered-file-system/empty-dir.d.ts +7 -0
- package/dist/powered-file-system/empty-dir.js +28 -0
- package/dist/powered-file-system/empty-dir.test.d.ts +1 -0
- package/dist/powered-file-system/empty-dir.test.js +61 -0
- package/dist/powered-file-system/readlink.d.ts +8 -0
- package/dist/powered-file-system/readlink.js +26 -0
- package/dist/powered-file-system/readlink.test.d.ts +1 -0
- package/dist/powered-file-system/readlink.test.js +44 -0
- package/dist/powered-file-system/realpath.d.ts +8 -0
- package/dist/powered-file-system/realpath.js +26 -0
- package/dist/powered-file-system/realpath.test.d.ts +1 -0
- package/dist/powered-file-system/realpath.test.js +44 -0
- package/dist/powered-file-system.d.ts +23 -0
- package/dist/powered-file-system.js +21 -0
- package/dist/recurse-io-sync.d.ts +6 -1
- package/dist/recurse-io-sync.js +30 -10
- package/dist/recurse-io.d.ts +10 -1
- package/dist/recurse-io.js +109 -26
- package/package.json +1 -1
- package/readme.md +104 -2
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { PoweredFileSystem } from '../powered-file-system';
|
|
1
|
+
import type { CopyFilter, PoweredFileSystem } from '../powered-file-system';
|
|
2
2
|
/**
|
|
3
3
|
* Resolves source and destination paths before delegating recursive copy work.
|
|
4
4
|
*/
|
|
5
5
|
export declare function copy<T extends boolean = false>(this: PoweredFileSystem, src: string, dest: string, options?: {
|
|
6
6
|
sync?: T;
|
|
7
7
|
umask?: number;
|
|
8
|
+
overwrite?: boolean;
|
|
9
|
+
filter?: CopyFilter;
|
|
8
10
|
}): T extends true ? void : Promise<void>;
|
|
@@ -13,13 +13,14 @@ const recurse_io_sync_1 = require("../recurse-io-sync");
|
|
|
13
13
|
function copy(src, dest, options) {
|
|
14
14
|
src = node_path_1.default.resolve(this.pwd, src);
|
|
15
15
|
dest = node_path_1.default.resolve(this.pwd, dest);
|
|
16
|
-
const { sync = false, umask = 0o000 } = options ?? {};
|
|
16
|
+
const { sync = false, umask = 0o000, overwrite = false, filter } = options ?? {};
|
|
17
|
+
const copyOptions = { umask, overwrite, filter };
|
|
17
18
|
if (sync) {
|
|
18
|
-
(0, recurse_io_sync_1.copySync)(src, dest,
|
|
19
|
+
(0, recurse_io_sync_1.copySync)(src, dest, copyOptions);
|
|
19
20
|
return undefined;
|
|
20
21
|
}
|
|
21
22
|
return new Promise((resolve, reject) => {
|
|
22
|
-
(0, recurse_io_1.copy)(src, dest,
|
|
23
|
+
(0, recurse_io_1.copy)(src, dest, copyOptions, (err) => {
|
|
23
24
|
if (err) {
|
|
24
25
|
return reject(err);
|
|
25
26
|
}
|
|
@@ -50,6 +50,28 @@ const test_utils_1 = require("../test-utils");
|
|
|
50
50
|
await index_1.pfs.copy(tmpDir, node_path_1.default.dirname(tmpDir));
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
|
+
(0, node_test_1.it)('Positive: Overwrite should replace an existing target file', async () => {
|
|
54
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(tmpDir, 'digest', 'tings.txt'), 'old');
|
|
55
|
+
await index_1.pfs.copy(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'digest'), {
|
|
56
|
+
overwrite: true
|
|
57
|
+
});
|
|
58
|
+
const content = node_fs_1.default.readFileSync(node_path_1.default.join(tmpDir, 'digest', 'tings.txt'), 'utf8');
|
|
59
|
+
(0, node_assert_1.default)(content !== 'old');
|
|
60
|
+
});
|
|
61
|
+
(0, node_test_1.it)('Positive: Filter should skip matching entries', async () => {
|
|
62
|
+
const destRoot = (0, test_utils_1.createTmpDir)();
|
|
63
|
+
try {
|
|
64
|
+
await index_1.pfs.copy(tmpDir, destRoot, {
|
|
65
|
+
overwrite: true,
|
|
66
|
+
filter: (src) => node_path_1.default.basename(src) !== 'tings.txt'
|
|
67
|
+
});
|
|
68
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(node_path_1.default.join(destRoot, node_path_1.default.basename(tmpDir), 'digest')));
|
|
69
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(node_path_1.default.join(destRoot, node_path_1.default.basename(tmpDir), 'tings.txt')) === false);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
(0, test_utils_1.restore)(destRoot);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
53
75
|
(0, node_test_1.it)('[sync] Positive: Copying a file', () => {
|
|
54
76
|
index_1.pfs.copy(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'digest'), {
|
|
55
77
|
sync: true
|
|
@@ -79,4 +101,28 @@ const test_utils_1 = require("../test-utils");
|
|
|
79
101
|
});
|
|
80
102
|
});
|
|
81
103
|
});
|
|
104
|
+
(0, node_test_1.it)('[sync] Positive: Overwrite should replace an existing target file', () => {
|
|
105
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(tmpDir, 'digest', 'tings.txt'), 'old');
|
|
106
|
+
index_1.pfs.copy(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'digest'), {
|
|
107
|
+
sync: true,
|
|
108
|
+
overwrite: true
|
|
109
|
+
});
|
|
110
|
+
const content = node_fs_1.default.readFileSync(node_path_1.default.join(tmpDir, 'digest', 'tings.txt'), 'utf8');
|
|
111
|
+
(0, node_assert_1.default)(content !== 'old');
|
|
112
|
+
});
|
|
113
|
+
(0, node_test_1.it)('[sync] Positive: Filter should skip matching entries', () => {
|
|
114
|
+
const destRoot = (0, test_utils_1.createTmpDir)();
|
|
115
|
+
try {
|
|
116
|
+
index_1.pfs.copy(tmpDir, destRoot, {
|
|
117
|
+
sync: true,
|
|
118
|
+
overwrite: true,
|
|
119
|
+
filter: (src) => node_path_1.default.basename(src) !== 'tings.txt'
|
|
120
|
+
});
|
|
121
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(node_path_1.default.join(destRoot, node_path_1.default.basename(tmpDir), 'digest')));
|
|
122
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(node_path_1.default.join(destRoot, node_path_1.default.basename(tmpDir), 'tings.txt')) === false);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
(0, test_utils_1.restore)(destRoot);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
82
128
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PoweredFileSystem } from '../powered-file-system';
|
|
2
|
+
/**
|
|
3
|
+
* Removes directory contents while preserving the directory itself.
|
|
4
|
+
*/
|
|
5
|
+
export declare function emptyDir<T extends boolean = false>(this: PoweredFileSystem, src: string, options?: {
|
|
6
|
+
sync?: T;
|
|
7
|
+
}): T extends true ? void : Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.emptyDir = emptyDir;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const recurse_io_1 = require("../recurse-io");
|
|
9
|
+
const recurse_io_sync_1 = require("../recurse-io-sync");
|
|
10
|
+
/**
|
|
11
|
+
* Removes directory contents while preserving the directory itself.
|
|
12
|
+
*/
|
|
13
|
+
function emptyDir(src, options) {
|
|
14
|
+
src = node_path_1.default.resolve(this.pwd, src);
|
|
15
|
+
const { sync = false } = options ?? {};
|
|
16
|
+
if (sync) {
|
|
17
|
+
(0, recurse_io_sync_1.emptyDirSync)(src);
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
(0, recurse_io_1.emptyDir)(src, (err) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
return reject(err);
|
|
24
|
+
}
|
|
25
|
+
resolve();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const chance_1 = __importDefault(require("chance"));
|
|
10
|
+
const node_test_1 = require("node:test");
|
|
11
|
+
const index_1 = require("../index");
|
|
12
|
+
const test_utils_1 = require("../test-utils");
|
|
13
|
+
/**
|
|
14
|
+
* Verifies directory cleanup while preserving the directory itself.
|
|
15
|
+
*/
|
|
16
|
+
(0, node_test_1.describe)('emptyDir(src [, options])', () => {
|
|
17
|
+
const chance = new chance_1.default();
|
|
18
|
+
let tmpDir = '';
|
|
19
|
+
(0, node_test_1.beforeEach)(() => {
|
|
20
|
+
tmpDir = (0, test_utils_1.createTmpDir)();
|
|
21
|
+
const frame = {
|
|
22
|
+
[node_path_1.default.join(tmpDir, 'tings.txt')]: {
|
|
23
|
+
type: 'file',
|
|
24
|
+
data: chance.string()
|
|
25
|
+
},
|
|
26
|
+
[node_path_1.default.join(tmpDir, 'digest')]: { type: 'directory' },
|
|
27
|
+
[node_path_1.default.join(tmpDir, 'digest', 'nested.txt')]: {
|
|
28
|
+
type: 'file',
|
|
29
|
+
data: chance.string()
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
(0, test_utils_1.fmock)(frame);
|
|
33
|
+
});
|
|
34
|
+
(0, node_test_1.afterEach)(() => {
|
|
35
|
+
(0, test_utils_1.restore)(tmpDir);
|
|
36
|
+
});
|
|
37
|
+
(0, node_test_1.it)('Positive: Removes all directory contents but preserves the directory', async () => {
|
|
38
|
+
await index_1.pfs.emptyDir(tmpDir);
|
|
39
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(tmpDir));
|
|
40
|
+
node_assert_1.default.deepStrictEqual(node_fs_1.default.readdirSync(tmpDir), []);
|
|
41
|
+
});
|
|
42
|
+
(0, node_test_1.it)('Negative: Throw if resource is not directory', async () => {
|
|
43
|
+
await node_assert_1.default.rejects(async () => {
|
|
44
|
+
await index_1.pfs.emptyDir(node_path_1.default.join(tmpDir, 'tings.txt'));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
(0, node_test_1.it)('[sync] Positive: Removes all directory contents but preserves the directory', () => {
|
|
48
|
+
index_1.pfs.emptyDir(tmpDir, {
|
|
49
|
+
sync: true
|
|
50
|
+
});
|
|
51
|
+
(0, node_assert_1.default)(node_fs_1.default.existsSync(tmpDir));
|
|
52
|
+
node_assert_1.default.deepStrictEqual(node_fs_1.default.readdirSync(tmpDir), []);
|
|
53
|
+
});
|
|
54
|
+
(0, node_test_1.it)('[sync] Negative: Throw if resource is not directory', () => {
|
|
55
|
+
node_assert_1.default.throws(() => {
|
|
56
|
+
index_1.pfs.emptyDir(node_path_1.default.join(tmpDir, 'tings.txt'), {
|
|
57
|
+
sync: true
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PoweredFileSystem } from '../powered-file-system';
|
|
2
|
+
/**
|
|
3
|
+
* Reads the target path stored in a symbolic link.
|
|
4
|
+
*/
|
|
5
|
+
export declare function readlink<T extends boolean = false>(this: PoweredFileSystem, src: string, options?: {
|
|
6
|
+
sync?: T;
|
|
7
|
+
encoding?: BufferEncoding;
|
|
8
|
+
}): T extends true ? string : Promise<string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.readlink = readlink;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
/**
|
|
10
|
+
* Reads the target path stored in a symbolic link.
|
|
11
|
+
*/
|
|
12
|
+
function readlink(src, options) {
|
|
13
|
+
src = node_path_1.default.resolve(this.pwd, src);
|
|
14
|
+
const { sync = false, encoding = 'utf8' } = options ?? {};
|
|
15
|
+
if (sync) {
|
|
16
|
+
return node_fs_1.default.readlinkSync(src, { encoding });
|
|
17
|
+
}
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
node_fs_1.default.readlink(src, { encoding }, (err, resolved) => {
|
|
20
|
+
if (err) {
|
|
21
|
+
return reject(err);
|
|
22
|
+
}
|
|
23
|
+
resolve(resolved);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const chance_1 = __importDefault(require("chance"));
|
|
9
|
+
const node_test_1 = require("node:test");
|
|
10
|
+
const index_1 = require("../index");
|
|
11
|
+
const test_utils_1 = require("../test-utils");
|
|
12
|
+
/**
|
|
13
|
+
* Verifies symbolic link target resolution without dereferencing it.
|
|
14
|
+
*/
|
|
15
|
+
(0, node_test_1.describe)('readlink(src [, options])', () => {
|
|
16
|
+
const chance = new chance_1.default();
|
|
17
|
+
let tmpDir = '';
|
|
18
|
+
(0, node_test_1.beforeEach)(() => {
|
|
19
|
+
tmpDir = (0, test_utils_1.createTmpDir)();
|
|
20
|
+
(0, test_utils_1.fmock)({
|
|
21
|
+
[node_path_1.default.join(tmpDir, 'tings.txt')]: {
|
|
22
|
+
type: 'file',
|
|
23
|
+
data: chance.string()
|
|
24
|
+
},
|
|
25
|
+
[node_path_1.default.join(tmpDir, 'flexapp')]: {
|
|
26
|
+
type: 'symlink',
|
|
27
|
+
target: node_path_1.default.join(tmpDir, 'tings.txt')
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
(0, node_test_1.afterEach)(() => {
|
|
32
|
+
(0, test_utils_1.restore)(tmpDir);
|
|
33
|
+
});
|
|
34
|
+
(0, node_test_1.it)('Positive: Reads the stored symlink target', async () => {
|
|
35
|
+
const target = await index_1.pfs.readlink(node_path_1.default.join(tmpDir, 'flexapp'));
|
|
36
|
+
(0, node_assert_1.default)(target === node_path_1.default.join(tmpDir, 'tings.txt'));
|
|
37
|
+
});
|
|
38
|
+
(0, node_test_1.it)('[sync] Positive: Reads the stored symlink target', () => {
|
|
39
|
+
const target = index_1.pfs.readlink(node_path_1.default.join(tmpDir, 'flexapp'), {
|
|
40
|
+
sync: true
|
|
41
|
+
});
|
|
42
|
+
(0, node_assert_1.default)(target === node_path_1.default.join(tmpDir, 'tings.txt'));
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PoweredFileSystem } from '../powered-file-system';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a path to its canonical absolute location.
|
|
4
|
+
*/
|
|
5
|
+
export declare function realpath<T extends boolean = false>(this: PoweredFileSystem, src: string, options?: {
|
|
6
|
+
sync?: T;
|
|
7
|
+
encoding?: BufferEncoding;
|
|
8
|
+
}): T extends true ? string : Promise<string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.realpath = realpath;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a path to its canonical absolute location.
|
|
11
|
+
*/
|
|
12
|
+
function realpath(src, options) {
|
|
13
|
+
src = node_path_1.default.resolve(this.pwd, src);
|
|
14
|
+
const { sync = false, encoding = 'utf8' } = options ?? {};
|
|
15
|
+
if (sync) {
|
|
16
|
+
return node_fs_1.default.realpathSync(src, { encoding });
|
|
17
|
+
}
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
node_fs_1.default.realpath(src, { encoding }, (err, resolved) => {
|
|
20
|
+
if (err) {
|
|
21
|
+
return reject(err);
|
|
22
|
+
}
|
|
23
|
+
resolve(resolved);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const chance_1 = __importDefault(require("chance"));
|
|
9
|
+
const node_test_1 = require("node:test");
|
|
10
|
+
const index_1 = require("../index");
|
|
11
|
+
const test_utils_1 = require("../test-utils");
|
|
12
|
+
/**
|
|
13
|
+
* Verifies canonical path resolution through symbolic links.
|
|
14
|
+
*/
|
|
15
|
+
(0, node_test_1.describe)('realpath(src [, options])', () => {
|
|
16
|
+
const chance = new chance_1.default();
|
|
17
|
+
let tmpDir = '';
|
|
18
|
+
(0, node_test_1.beforeEach)(() => {
|
|
19
|
+
tmpDir = (0, test_utils_1.createTmpDir)();
|
|
20
|
+
(0, test_utils_1.fmock)({
|
|
21
|
+
[node_path_1.default.join(tmpDir, 'tings.txt')]: {
|
|
22
|
+
type: 'file',
|
|
23
|
+
data: chance.string()
|
|
24
|
+
},
|
|
25
|
+
[node_path_1.default.join(tmpDir, 'flexapp')]: {
|
|
26
|
+
type: 'symlink',
|
|
27
|
+
target: node_path_1.default.join(tmpDir, 'tings.txt')
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
(0, node_test_1.afterEach)(() => {
|
|
32
|
+
(0, test_utils_1.restore)(tmpDir);
|
|
33
|
+
});
|
|
34
|
+
(0, node_test_1.it)('Positive: Resolves the canonical target path', async () => {
|
|
35
|
+
const target = await index_1.pfs.realpath(node_path_1.default.join(tmpDir, 'flexapp'));
|
|
36
|
+
(0, node_assert_1.default)(target === node_path_1.default.join(tmpDir, 'tings.txt'));
|
|
37
|
+
});
|
|
38
|
+
(0, node_test_1.it)('[sync] Positive: Resolves the canonical target path', () => {
|
|
39
|
+
const target = index_1.pfs.realpath(node_path_1.default.join(tmpDir, 'flexapp'), {
|
|
40
|
+
sync: true
|
|
41
|
+
});
|
|
42
|
+
(0, node_assert_1.default)(target === node_path_1.default.join(tmpDir, 'tings.txt'));
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -6,6 +6,7 @@ import { bitmask } from './bitmask';
|
|
|
6
6
|
export type Mode = keyof IConstants;
|
|
7
7
|
export type Flag = Extract<fs.OpenMode, string>;
|
|
8
8
|
export type Stats = fs.Stats;
|
|
9
|
+
export type CopyFilter = (src: string, dest: string) => boolean;
|
|
9
10
|
export * from './bitmask';
|
|
10
11
|
export interface IConstants {
|
|
11
12
|
e: number;
|
|
@@ -72,6 +73,8 @@ export declare class PoweredFileSystem {
|
|
|
72
73
|
copy<T extends boolean = false>(src: string, dest: string, options?: {
|
|
73
74
|
sync?: T;
|
|
74
75
|
umask?: number;
|
|
76
|
+
overwrite?: boolean;
|
|
77
|
+
filter?: CopyFilter;
|
|
75
78
|
}): T extends true ? void : Promise<void>;
|
|
76
79
|
/**
|
|
77
80
|
* Renames or moves a file system node.
|
|
@@ -85,6 +88,12 @@ export declare class PoweredFileSystem {
|
|
|
85
88
|
remove<T extends boolean = false>(src: string, options?: {
|
|
86
89
|
sync?: T;
|
|
87
90
|
}): T extends true ? void : Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Removes all directory entries while preserving the directory itself.
|
|
93
|
+
*/
|
|
94
|
+
emptyDir<T extends boolean = false>(src: string, options?: {
|
|
95
|
+
sync?: T;
|
|
96
|
+
}): T extends true ? void : Promise<void>;
|
|
88
97
|
/**
|
|
89
98
|
* Reads a file relative to the current instance root.
|
|
90
99
|
*/
|
|
@@ -117,6 +126,20 @@ export declare class PoweredFileSystem {
|
|
|
117
126
|
sync?: T;
|
|
118
127
|
encoding?: BufferEncoding | null;
|
|
119
128
|
}): T extends true ? string[] : Promise<string[]>;
|
|
129
|
+
/**
|
|
130
|
+
* Resolves the target of a symbolic link.
|
|
131
|
+
*/
|
|
132
|
+
readlink<T extends boolean = false>(src: string, options?: {
|
|
133
|
+
sync?: T;
|
|
134
|
+
encoding?: BufferEncoding;
|
|
135
|
+
}): T extends true ? string : Promise<string>;
|
|
136
|
+
/**
|
|
137
|
+
* Resolves a path to its canonical absolute location.
|
|
138
|
+
*/
|
|
139
|
+
realpath<T extends boolean = false>(src: string, options?: {
|
|
140
|
+
sync?: T;
|
|
141
|
+
encoding?: BufferEncoding;
|
|
142
|
+
}): T extends true ? string : Promise<string>;
|
|
120
143
|
/**
|
|
121
144
|
* Creates a directory tree relative to the current instance root.
|
|
122
145
|
*/
|
|
@@ -25,9 +25,12 @@ const append_1 = require("./powered-file-system/append");
|
|
|
25
25
|
const chmod_1 = require("./powered-file-system/chmod");
|
|
26
26
|
const chown_1 = require("./powered-file-system/chown");
|
|
27
27
|
const copy_1 = require("./powered-file-system/copy");
|
|
28
|
+
const empty_dir_1 = require("./powered-file-system/empty-dir");
|
|
28
29
|
const mkdir_1 = require("./powered-file-system/mkdir");
|
|
29
30
|
const read_1 = require("./powered-file-system/read");
|
|
31
|
+
const readlink_1 = require("./powered-file-system/readlink");
|
|
30
32
|
const readdir_1 = require("./powered-file-system/readdir");
|
|
33
|
+
const realpath_1 = require("./powered-file-system/realpath");
|
|
31
34
|
const remove_1 = require("./powered-file-system/remove");
|
|
32
35
|
const rename_1 = require("./powered-file-system/rename");
|
|
33
36
|
const stat_1 = require("./powered-file-system/stat");
|
|
@@ -110,6 +113,12 @@ class PoweredFileSystem {
|
|
|
110
113
|
remove(src, options) {
|
|
111
114
|
return remove_1.remove.call(this, src, options);
|
|
112
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Removes all directory entries while preserving the directory itself.
|
|
118
|
+
*/
|
|
119
|
+
emptyDir(src, options) {
|
|
120
|
+
return empty_dir_1.emptyDir.call(this, src, options);
|
|
121
|
+
}
|
|
113
122
|
/**
|
|
114
123
|
* Reads a file relative to the current instance root.
|
|
115
124
|
*/
|
|
@@ -134,6 +143,18 @@ class PoweredFileSystem {
|
|
|
134
143
|
readdir(dir, options) {
|
|
135
144
|
return readdir_1.readdir.call(this, dir, options);
|
|
136
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolves the target of a symbolic link.
|
|
148
|
+
*/
|
|
149
|
+
readlink(src, options) {
|
|
150
|
+
return readlink_1.readlink.call(this, src, options);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Resolves a path to its canonical absolute location.
|
|
154
|
+
*/
|
|
155
|
+
realpath(src, options) {
|
|
156
|
+
return realpath_1.realpath.call(this, src, options);
|
|
157
|
+
}
|
|
137
158
|
/**
|
|
138
159
|
* Creates a directory tree relative to the current instance root.
|
|
139
160
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ICopyOptions } from './recurse-io';
|
|
1
2
|
/**
|
|
2
3
|
* Synchronous counterpart of the recursive chmod implementation.
|
|
3
4
|
*/
|
|
@@ -9,11 +10,15 @@ export declare function chownSync(src: string, uid: number, gid: number): void;
|
|
|
9
10
|
/**
|
|
10
11
|
* Synchronously copies a file system node into the target directory.
|
|
11
12
|
*/
|
|
12
|
-
export declare function copySync(src: string, dir: string,
|
|
13
|
+
export declare function copySync(src: string, dir: string, options: ICopyOptions): void;
|
|
13
14
|
/**
|
|
14
15
|
* Synchronously removes files, directories, and symlinks without following links.
|
|
15
16
|
*/
|
|
16
17
|
export declare function removeSync(src: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Synchronously removes all entries inside a directory while preserving it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function emptyDirSync(src: string): void;
|
|
17
22
|
/**
|
|
18
23
|
* Synchronously creates a directory tree using permissions derived from umask.
|
|
19
24
|
*/
|
package/dist/recurse-io-sync.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.chmodSync = chmodSync;
|
|
|
7
7
|
exports.chownSync = chownSync;
|
|
8
8
|
exports.copySync = copySync;
|
|
9
9
|
exports.removeSync = removeSync;
|
|
10
|
+
exports.emptyDirSync = emptyDirSync;
|
|
10
11
|
exports.mkdirSync = mkdirSync;
|
|
11
12
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -45,23 +46,33 @@ function chownSync(src, uid, gid) {
|
|
|
45
46
|
/**
|
|
46
47
|
* Synchronously copies a file system node into the target directory.
|
|
47
48
|
*/
|
|
48
|
-
function copySync(src, dir,
|
|
49
|
+
function copySync(src, dir, options) {
|
|
49
50
|
const stat = node_fs_1.default.statSync(src);
|
|
51
|
+
const loc = node_path_1.default.basename(src);
|
|
52
|
+
const dest = node_path_1.default.join(dir, loc);
|
|
53
|
+
if (dest === src) {
|
|
54
|
+
throw new Error(`Source and destination are identical: ${src}`);
|
|
55
|
+
}
|
|
56
|
+
if (options.filter && options.filter(src, dest) === false) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
50
59
|
if (stat.isDirectory()) {
|
|
51
60
|
const list = node_fs_1.default.readdirSync(src);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
const mode = 0o777 & ~options.umask;
|
|
62
|
+
if (options.overwrite && node_fs_1.default.existsSync(dest)) {
|
|
63
|
+
removeSync(dest);
|
|
64
|
+
}
|
|
65
|
+
node_fs_1.default.mkdirSync(dest, { mode });
|
|
56
66
|
for (const loc of list) {
|
|
57
|
-
copySync(node_path_1.default.join(src, loc),
|
|
67
|
+
copySync(node_path_1.default.join(src, loc), dest, options);
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
else {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
node_fs_1.default.
|
|
71
|
+
if (options.overwrite && node_fs_1.default.existsSync(dest)) {
|
|
72
|
+
removeSync(dest);
|
|
73
|
+
}
|
|
74
|
+
node_fs_1.default.copyFileSync(src, dest);
|
|
75
|
+
node_fs_1.default.chmodSync(dest, 0o666 & ~options.umask);
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
/**
|
|
@@ -84,6 +95,15 @@ function removeSync(src) {
|
|
|
84
95
|
node_fs_1.default.unlinkSync(src);
|
|
85
96
|
}
|
|
86
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Synchronously removes all entries inside a directory while preserving it.
|
|
100
|
+
*/
|
|
101
|
+
function emptyDirSync(src) {
|
|
102
|
+
const list = node_fs_1.default.readdirSync(src);
|
|
103
|
+
for (const loc of list) {
|
|
104
|
+
removeSync(node_path_1.default.join(src, loc));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
87
107
|
/**
|
|
88
108
|
* Synchronously creates a directory tree using permissions derived from umask.
|
|
89
109
|
*/
|
package/dist/recurse-io.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { NoParamCallback } from 'node:fs';
|
|
2
|
+
export interface ICopyOptions {
|
|
3
|
+
umask: number;
|
|
4
|
+
overwrite: boolean;
|
|
5
|
+
filter?: (src: string, dest: string) => boolean;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Applies chmod depth-first so directories are updated after their contents.
|
|
4
9
|
*/
|
|
@@ -10,11 +15,15 @@ export declare function chown(src: string, uid: number, gid: number, callback: N
|
|
|
10
15
|
/**
|
|
11
16
|
* Copies a file system node into the target directory, creating directories as needed.
|
|
12
17
|
*/
|
|
13
|
-
export declare function copy(src: string, dir: string,
|
|
18
|
+
export declare function copy(src: string, dir: string, options: ICopyOptions, callback: NoParamCallback): void;
|
|
14
19
|
/**
|
|
15
20
|
* Removes files, directories, and symlinks without following symbolic links.
|
|
16
21
|
*/
|
|
17
22
|
export declare function remove(src: string, callback: NoParamCallback): void;
|
|
23
|
+
/**
|
|
24
|
+
* Removes all entries inside a directory while preserving the directory itself.
|
|
25
|
+
*/
|
|
26
|
+
export declare function emptyDir(src: string, callback: NoParamCallback): void;
|
|
18
27
|
/**
|
|
19
28
|
* Creates a directory tree with the permissions derived from the provided umask.
|
|
20
29
|
*/
|
package/dist/recurse-io.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.chmod = chmod;
|
|
|
7
7
|
exports.chown = chown;
|
|
8
8
|
exports.copy = copy;
|
|
9
9
|
exports.remove = remove;
|
|
10
|
+
exports.emptyDir = emptyDir;
|
|
10
11
|
exports.mkdir = mkdir;
|
|
11
12
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -88,55 +89,113 @@ function chown(src, uid, gid, callback) {
|
|
|
88
89
|
/**
|
|
89
90
|
* Copies a file system node into the target directory, creating directories as needed.
|
|
90
91
|
*/
|
|
91
|
-
function copy(src, dir,
|
|
92
|
+
function copy(src, dir, options, callback) {
|
|
92
93
|
node_fs_1.default.stat(src, (err, stat) => {
|
|
93
94
|
if (err) {
|
|
94
95
|
return callback(err);
|
|
95
96
|
}
|
|
97
|
+
const loc = node_path_1.default.basename(src);
|
|
98
|
+
const dest = node_path_1.default.join(dir, loc);
|
|
99
|
+
if (dest === src) {
|
|
100
|
+
return callback(new Error(`Source and destination are identical: ${src}`));
|
|
101
|
+
}
|
|
102
|
+
if (options.filter && options.filter(src, dest) === false) {
|
|
103
|
+
return callback(null);
|
|
104
|
+
}
|
|
96
105
|
if (stat.isDirectory()) {
|
|
97
106
|
node_fs_1.default.readdir(src, (err, list) => {
|
|
98
107
|
if (err) {
|
|
99
108
|
return callback(err);
|
|
100
109
|
}
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
const mode = 0o777 & ~options.umask;
|
|
111
|
+
const create = () => {
|
|
112
|
+
node_fs_1.default.mkdir(dest, { mode }, (err) => {
|
|
113
|
+
if (err) {
|
|
114
|
+
if (err.code === 'EEXIST') {
|
|
115
|
+
err = new Error(`Target already exists: ${dest}`);
|
|
116
|
+
}
|
|
117
|
+
return callback(err);
|
|
118
|
+
}
|
|
119
|
+
if (list.length === 0) {
|
|
120
|
+
return callback(null);
|
|
121
|
+
}
|
|
122
|
+
let reduce = list.length;
|
|
123
|
+
for (const item of list) {
|
|
124
|
+
copy(node_path_1.default.join(src, item), dest, options, (err) => {
|
|
125
|
+
if (err) {
|
|
126
|
+
return callback(err);
|
|
127
|
+
}
|
|
128
|
+
if (--reduce === 0) {
|
|
129
|
+
callback(null);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
if (!options.overwrite) {
|
|
136
|
+
return create();
|
|
137
|
+
}
|
|
138
|
+
node_fs_1.default.lstat(dest, (err, destStat) => {
|
|
105
139
|
if (err) {
|
|
106
|
-
if (err.code === '
|
|
107
|
-
|
|
140
|
+
if (err.code === 'ENOENT') {
|
|
141
|
+
return create();
|
|
108
142
|
}
|
|
109
143
|
return callback(err);
|
|
110
144
|
}
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
let reduce = list.length;
|
|
115
|
-
for (const item of list) {
|
|
116
|
-
copy(node_path_1.default.join(src, item), destDir, umask, (err) => {
|
|
145
|
+
if (destStat.isDirectory()) {
|
|
146
|
+
return remove(dest, (err) => {
|
|
117
147
|
if (err) {
|
|
118
148
|
return callback(err);
|
|
119
149
|
}
|
|
120
|
-
|
|
121
|
-
callback(null);
|
|
122
|
-
}
|
|
150
|
+
create();
|
|
123
151
|
});
|
|
124
152
|
}
|
|
153
|
+
node_fs_1.default.unlink(dest, (err) => {
|
|
154
|
+
if (err) {
|
|
155
|
+
return callback(err);
|
|
156
|
+
}
|
|
157
|
+
create();
|
|
158
|
+
});
|
|
125
159
|
});
|
|
126
160
|
});
|
|
127
161
|
}
|
|
128
162
|
else {
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
163
|
+
const mode = 0o666 & ~options.umask;
|
|
164
|
+
const write = () => {
|
|
165
|
+
const readStream = node_fs_1.default.createReadStream(src);
|
|
166
|
+
const writeStream = node_fs_1.default.createWriteStream(dest, { mode });
|
|
167
|
+
readStream.on('error', callback);
|
|
168
|
+
writeStream.on('error', callback);
|
|
169
|
+
writeStream.on('close', () => {
|
|
170
|
+
node_fs_1.default.chmod(dest, mode, callback);
|
|
171
|
+
});
|
|
172
|
+
readStream.pipe(writeStream);
|
|
173
|
+
};
|
|
174
|
+
if (!options.overwrite) {
|
|
175
|
+
return write();
|
|
176
|
+
}
|
|
177
|
+
node_fs_1.default.lstat(dest, (err, destStat) => {
|
|
178
|
+
if (err) {
|
|
179
|
+
if (err.code === 'ENOENT') {
|
|
180
|
+
return write();
|
|
181
|
+
}
|
|
182
|
+
return callback(err);
|
|
183
|
+
}
|
|
184
|
+
if (destStat.isDirectory()) {
|
|
185
|
+
return remove(dest, (err) => {
|
|
186
|
+
if (err) {
|
|
187
|
+
return callback(err);
|
|
188
|
+
}
|
|
189
|
+
write();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
node_fs_1.default.unlink(dest, (err) => {
|
|
193
|
+
if (err) {
|
|
194
|
+
return callback(err);
|
|
195
|
+
}
|
|
196
|
+
write();
|
|
197
|
+
});
|
|
138
198
|
});
|
|
139
|
-
readStream.pipe(writeStream);
|
|
140
199
|
}
|
|
141
200
|
});
|
|
142
201
|
}
|
|
@@ -177,6 +236,30 @@ function remove(src, callback) {
|
|
|
177
236
|
}
|
|
178
237
|
});
|
|
179
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Removes all entries inside a directory while preserving the directory itself.
|
|
241
|
+
*/
|
|
242
|
+
function emptyDir(src, callback) {
|
|
243
|
+
node_fs_1.default.readdir(src, (err, list) => {
|
|
244
|
+
if (err) {
|
|
245
|
+
return callback(err);
|
|
246
|
+
}
|
|
247
|
+
if (list.length === 0) {
|
|
248
|
+
return callback(null);
|
|
249
|
+
}
|
|
250
|
+
let reduce = list.length;
|
|
251
|
+
for (const loc of list) {
|
|
252
|
+
remove(node_path_1.default.join(src, loc), (err) => {
|
|
253
|
+
if (err) {
|
|
254
|
+
return callback(err);
|
|
255
|
+
}
|
|
256
|
+
if (--reduce === 0) {
|
|
257
|
+
callback(null);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
180
263
|
/**
|
|
181
264
|
* Creates a directory tree with the permissions derived from the provided umask.
|
|
182
265
|
*/
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -31,6 +31,42 @@ It is especially useful for:
|
|
|
31
31
|
npm install pwd-fs
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Table of Contents
|
|
35
|
+
|
|
36
|
+
- [Quick Start](#quick-start)
|
|
37
|
+
- [Common Recipes](#common-recipes)
|
|
38
|
+
- [Compatibility](#compatibility)
|
|
39
|
+
- [Exports](#exports)
|
|
40
|
+
- [API](#api)
|
|
41
|
+
- [`new PoweredFileSystem(pwd?)`](#new-poweredfilesystempwd)
|
|
42
|
+
- [`pfs.pwd`](#pfspwd)
|
|
43
|
+
- [`pfs.constants`](#pfsconstants)
|
|
44
|
+
- [`PoweredFileSystem.bitmask(mode)`](#poweredfilesystembitmaskmode)
|
|
45
|
+
- [`pfs.test(src, options?)`](#pfstestsrc-options)
|
|
46
|
+
- [`pfs.stat(src, options?)`](#pfsstatsrc-options)
|
|
47
|
+
- [`pfs.chmod(src, mode, options?)`](#pfschmodsrc-mode-options)
|
|
48
|
+
- [`pfs.chown(src, options?)`](#pfschownsrc-options)
|
|
49
|
+
- [`pfs.symlink(src, dest, options?)`](#pfssymlinksrc-dest-options)
|
|
50
|
+
- [`pfs.copy(src, dest, options?)`](#pfscopysrc-dest-options)
|
|
51
|
+
- [`pfs.rename(src, dest, options?)`](#pfsrenamesrc-dest-options)
|
|
52
|
+
- [`pfs.remove(src, options?)`](#pfsremovesrc-options)
|
|
53
|
+
- [`pfs.emptyDir(src, options?)`](#pfsemptydirsrc-options)
|
|
54
|
+
- [`pfs.read(src, options?)`](#pfsreadsrc-options)
|
|
55
|
+
- [`pfs.write(src, data, options?)`](#pfswritesrc-data-options)
|
|
56
|
+
- [`pfs.append(src, data, options?)`](#pfsappendsrc-data-options)
|
|
57
|
+
- [`pfs.readdir(dir, options?)`](#pfsreaddirdir-options)
|
|
58
|
+
- [`pfs.readlink(src, options?)`](#pfsreadlinksrc-options)
|
|
59
|
+
- [`pfs.realpath(src, options?)`](#pfsrealpathsrc-options)
|
|
60
|
+
- [`pfs.mkdir(dir, options?)`](#pfsmkdirdir-options)
|
|
61
|
+
- [Sync Mode](#sync-mode)
|
|
62
|
+
- [Error Behavior](#error-behavior)
|
|
63
|
+
- [Umask Behavior](#umask-behavior)
|
|
64
|
+
- [Notes](#notes)
|
|
65
|
+
- [Platform Caveats](#platform-caveats)
|
|
66
|
+
- [When To Use Native `fs`](#when-to-use-native-fs)
|
|
67
|
+
- [Development](#development)
|
|
68
|
+
- [License](#license)
|
|
69
|
+
|
|
34
70
|
## Quick Start
|
|
35
71
|
|
|
36
72
|
```ts
|
|
@@ -65,6 +101,19 @@ Result:
|
|
|
65
101
|
- destination directory: `./dist`
|
|
66
102
|
- created output: `./dist/assets`
|
|
67
103
|
|
|
104
|
+
### Empty a directory but keep it
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
await pfs.emptyDir('./cache');
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Resolve a symlink target
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const target = await pfs.readlink('./current');
|
|
114
|
+
const resolved = await pfs.realpath('./current');
|
|
115
|
+
```
|
|
116
|
+
|
|
68
117
|
### Append to a file
|
|
69
118
|
|
|
70
119
|
```ts
|
|
@@ -232,7 +281,12 @@ Copies `src` into the destination directory.
|
|
|
232
281
|
copy<T extends boolean = false>(
|
|
233
282
|
src: string,
|
|
234
283
|
dest: string,
|
|
235
|
-
options?: {
|
|
284
|
+
options?: {
|
|
285
|
+
sync?: T;
|
|
286
|
+
umask?: number;
|
|
287
|
+
overwrite?: boolean;
|
|
288
|
+
filter?: (src: string, dest: string) => boolean;
|
|
289
|
+
}
|
|
236
290
|
): T extends true ? void : Promise<void>
|
|
237
291
|
```
|
|
238
292
|
|
|
@@ -241,6 +295,8 @@ Behavior:
|
|
|
241
295
|
- copying a file creates `dest/<basename(src)>`
|
|
242
296
|
- copying a directory creates `dest/<basename(src)>` recursively
|
|
243
297
|
- the target must not already exist
|
|
298
|
+
- `overwrite: true` replaces an existing target entry with the same basename
|
|
299
|
+
- `filter()` can skip specific source entries during the copy
|
|
244
300
|
|
|
245
301
|
```ts
|
|
246
302
|
await pfs.copy('./assets', './dist');
|
|
@@ -248,6 +304,13 @@ await pfs.copy('./assets', './dist');
|
|
|
248
304
|
|
|
249
305
|
This creates `./dist/assets`, not a direct rename to `./dist`.
|
|
250
306
|
|
|
307
|
+
```ts
|
|
308
|
+
await pfs.copy('./assets', './dist', {
|
|
309
|
+
overwrite: true,
|
|
310
|
+
filter: (src) => !src.endsWith('.map')
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
251
314
|
### `pfs.rename(src, dest, options?)`
|
|
252
315
|
|
|
253
316
|
Renames or moves a file system entry.
|
|
@@ -276,6 +339,21 @@ Behavior:
|
|
|
276
339
|
- directories are removed recursively
|
|
277
340
|
- symbolic links are unlinked without deleting the target
|
|
278
341
|
|
|
342
|
+
### `pfs.emptyDir(src, options?)`
|
|
343
|
+
|
|
344
|
+
Removes all entries inside a directory while preserving the directory itself.
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
emptyDir<T extends boolean = false>(
|
|
348
|
+
src: string,
|
|
349
|
+
options?: { sync?: T }
|
|
350
|
+
): T extends true ? void : Promise<void>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
await pfs.emptyDir('./tmp');
|
|
355
|
+
```
|
|
356
|
+
|
|
279
357
|
### `pfs.read(src, options?)`
|
|
280
358
|
|
|
281
359
|
Reads a file.
|
|
@@ -363,6 +441,28 @@ readdir<T extends boolean = false>(
|
|
|
363
441
|
|
|
364
442
|
- default `encoding`: `'utf8'`
|
|
365
443
|
|
|
444
|
+
### `pfs.readlink(src, options?)`
|
|
445
|
+
|
|
446
|
+
Reads the stored target path from a symbolic link.
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
readlink<T extends boolean = false>(
|
|
450
|
+
src: string,
|
|
451
|
+
options?: { sync?: T; encoding?: BufferEncoding }
|
|
452
|
+
): T extends true ? string : Promise<string>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### `pfs.realpath(src, options?)`
|
|
456
|
+
|
|
457
|
+
Resolves a path to its canonical absolute location.
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
realpath<T extends boolean = false>(
|
|
461
|
+
src: string,
|
|
462
|
+
options?: { sync?: T; encoding?: BufferEncoding }
|
|
463
|
+
): T extends true ? string : Promise<string>
|
|
464
|
+
```
|
|
465
|
+
|
|
366
466
|
### `pfs.mkdir(dir, options?)`
|
|
367
467
|
|
|
368
468
|
Creates a directory tree recursively.
|
|
@@ -400,11 +500,13 @@ Typical cases:
|
|
|
400
500
|
- `test()` is the exception:
|
|
401
501
|
it returns `false` for inaccessible or missing paths instead of rejecting or throwing
|
|
402
502
|
- `read()`, `stat()`, `readdir()`, `chmod()`, `chown()`, `rename()`, and `remove()` fail for missing paths
|
|
503
|
+
- `readlink()` and `realpath()` fail for missing paths
|
|
403
504
|
- `read()` fails when the target is a directory
|
|
404
505
|
- `readdir()` fails when the target is not a directory
|
|
506
|
+
- `emptyDir()` fails when the target is not a directory
|
|
405
507
|
- `write()` fails when the target path points to a directory
|
|
406
508
|
- `copy()` fails when the source does not exist
|
|
407
|
-
- `copy()` also fails when the destination already contains an entry with the same basename as the source
|
|
509
|
+
- `copy()` also fails when the destination already contains an entry with the same basename as the source, unless `overwrite: true` is used
|
|
408
510
|
- `symlink()` fails when the destination already exists
|
|
409
511
|
- `mkdir()` accepts an existing directory, but fails when a path segment is a file
|
|
410
512
|
|