pwd-fs 3.4.0 → 3.5.4
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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/powered-file-system/append.d.ts +9 -6
- package/dist/powered-file-system/append.js +4 -4
- package/dist/powered-file-system/chmod.d.ts +4 -4
- package/dist/powered-file-system/chmod.js +9 -10
- package/dist/powered-file-system/chown.d.ts +7 -4
- package/dist/powered-file-system/chown.js +18 -8
- package/dist/powered-file-system/copy.d.ts +10 -7
- package/dist/powered-file-system/copy.js +11 -12
- package/dist/powered-file-system/empty-dir.d.ts +4 -4
- package/dist/powered-file-system/empty-dir.js +9 -10
- package/dist/powered-file-system/mkdir.d.ts +9 -6
- package/dist/powered-file-system/mkdir.js +9 -10
- package/dist/powered-file-system/read.d.ts +10 -6
- package/dist/powered-file-system/read.js +9 -5
- package/dist/powered-file-system/readdir.d.ts +11 -6
- package/dist/powered-file-system/readdir.js +8 -6
- package/dist/powered-file-system/readlink.d.ts +9 -4
- package/dist/powered-file-system/readlink.js +8 -6
- package/dist/powered-file-system/realpath.d.ts +9 -4
- package/dist/powered-file-system/realpath.js +8 -6
- package/dist/powered-file-system/remove.d.ts +5 -5
- package/dist/powered-file-system/remove.js +11 -20
- package/dist/powered-file-system/rename.d.ts +5 -5
- package/dist/powered-file-system/rename.js +11 -7
- package/dist/powered-file-system/stat.d.ts +4 -4
- package/dist/powered-file-system/stat.js +8 -6
- package/dist/powered-file-system/symlink.d.ts +4 -4
- package/dist/powered-file-system/symlink.js +11 -4
- package/dist/powered-file-system/test.d.ts +10 -5
- package/dist/powered-file-system/test.js +8 -5
- package/dist/powered-file-system/write.d.ts +10 -7
- package/dist/powered-file-system/write.js +9 -6
- package/dist/powered-file-system.d.ts +103 -56
- package/dist/powered-file-system.js +5 -48
- package/dist/powered-file-system.test.js +25 -0
- package/dist/recurse-io-sync.d.ts +1 -1
- package/dist/recurse-io-sync.js +11 -25
- package/dist/recurse-io.d.ts +1 -1
- package/dist/recurse-io.js +31 -49
- package/dist/suite.test.js +1 -1
- package/package.json +12 -17
- package/readme.md +30 -11
package/dist/recurse-io.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare function chmod(src: string, mode: number, callback: NoParamCallba
|
|
|
11
11
|
/**
|
|
12
12
|
* Applies ownership recursively while preserving current values when uid/gid are omitted.
|
|
13
13
|
*/
|
|
14
|
-
export declare function chown(src: string, uid: number, gid: number, callback: NoParamCallback): void;
|
|
14
|
+
export declare function chown(src: string, uid: number | undefined, gid: number | undefined, callback: NoParamCallback): void;
|
|
15
15
|
/**
|
|
16
16
|
* Copies a file system node into the target directory, creating directories as needed.
|
|
17
17
|
*/
|
package/dist/recurse-io.js
CHANGED
|
@@ -11,10 +11,22 @@ exports.emptyDir = emptyDir;
|
|
|
11
11
|
exports.mkdir = mkdir;
|
|
12
12
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
+
function once(callback) {
|
|
15
|
+
let called = false;
|
|
16
|
+
return (err) => {
|
|
17
|
+
// Recursive branches can fail concurrently; report only the first terminal result.
|
|
18
|
+
if (called) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
called = true;
|
|
22
|
+
callback(err);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
14
25
|
/**
|
|
15
26
|
* Applies chmod depth-first so directories are updated after their contents.
|
|
16
27
|
*/
|
|
17
28
|
function chmod(src, mode, callback) {
|
|
29
|
+
callback = once(callback);
|
|
18
30
|
let reduce = 0;
|
|
19
31
|
node_fs_1.default.stat(src, (err, stats) => {
|
|
20
32
|
if (err)
|
|
@@ -49,40 +61,38 @@ function chmod(src, mode, callback) {
|
|
|
49
61
|
* Applies ownership recursively while preserving current values when uid/gid are omitted.
|
|
50
62
|
*/
|
|
51
63
|
function chown(src, uid, gid, callback) {
|
|
64
|
+
callback = once(callback);
|
|
52
65
|
let reduce = 0;
|
|
53
66
|
node_fs_1.default.stat(src, (err, stats) => {
|
|
54
67
|
if (err) {
|
|
55
68
|
return callback(err);
|
|
56
69
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (gid === 0) {
|
|
61
|
-
gid = stats.gid;
|
|
62
|
-
}
|
|
70
|
+
// `0` is a valid uid/gid, so only nullish values mean "preserve current owner".
|
|
71
|
+
const nextUid = uid ?? stats.uid;
|
|
72
|
+
const nextGid = gid ?? stats.gid;
|
|
63
73
|
if (stats.isDirectory()) {
|
|
64
74
|
node_fs_1.default.readdir(src, (err, list) => {
|
|
65
75
|
if (err) {
|
|
66
76
|
return callback(err);
|
|
67
77
|
}
|
|
68
78
|
if (list.length === 0) {
|
|
69
|
-
return node_fs_1.default.chown(src,
|
|
79
|
+
return node_fs_1.default.chown(src, nextUid, nextGid, callback);
|
|
70
80
|
}
|
|
71
81
|
reduce = list.length;
|
|
72
82
|
for (const loc of list) {
|
|
73
|
-
chown(node_path_1.default.join(src, loc),
|
|
83
|
+
chown(node_path_1.default.join(src, loc), nextUid, nextGid, (err) => {
|
|
74
84
|
if (err) {
|
|
75
85
|
return callback(err);
|
|
76
86
|
}
|
|
77
87
|
if (--reduce === 0) {
|
|
78
|
-
node_fs_1.default.chown(src,
|
|
88
|
+
node_fs_1.default.chown(src, nextUid, nextGid, callback);
|
|
79
89
|
}
|
|
80
90
|
});
|
|
81
91
|
}
|
|
82
92
|
});
|
|
83
93
|
}
|
|
84
94
|
else {
|
|
85
|
-
node_fs_1.default.chown(src,
|
|
95
|
+
node_fs_1.default.chown(src, nextUid, nextGid, callback);
|
|
86
96
|
}
|
|
87
97
|
});
|
|
88
98
|
}
|
|
@@ -90,6 +100,7 @@ function chown(src, uid, gid, callback) {
|
|
|
90
100
|
* Copies a file system node into the target directory, creating directories as needed.
|
|
91
101
|
*/
|
|
92
102
|
function copy(src, dir, options, callback) {
|
|
103
|
+
callback = once(callback);
|
|
93
104
|
node_fs_1.default.stat(src, (err, stat) => {
|
|
94
105
|
if (err) {
|
|
95
106
|
return callback(err);
|
|
@@ -135,6 +146,7 @@ function copy(src, dir, options, callback) {
|
|
|
135
146
|
if (!options.overwrite) {
|
|
136
147
|
return create();
|
|
137
148
|
}
|
|
149
|
+
// Overwrite is implemented as replace-before-copy to support directory targets.
|
|
138
150
|
node_fs_1.default.lstat(dest, (err, destStat) => {
|
|
139
151
|
if (err) {
|
|
140
152
|
if (err.code === 'ENOENT') {
|
|
@@ -162,18 +174,18 @@ function copy(src, dir, options, callback) {
|
|
|
162
174
|
else {
|
|
163
175
|
const mode = 0o666 & ~options.umask;
|
|
164
176
|
const write = () => {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
177
|
+
const flags = options.overwrite ? 0 : node_fs_1.default.constants.COPYFILE_EXCL;
|
|
178
|
+
node_fs_1.default.copyFile(src, dest, flags, (err) => {
|
|
179
|
+
if (err) {
|
|
180
|
+
return callback(err);
|
|
181
|
+
}
|
|
170
182
|
node_fs_1.default.chmod(dest, mode, callback);
|
|
171
183
|
});
|
|
172
|
-
readStream.pipe(writeStream);
|
|
173
184
|
};
|
|
174
185
|
if (!options.overwrite) {
|
|
175
186
|
return write();
|
|
176
187
|
}
|
|
188
|
+
// Match directory behavior by replacing the existing target before writing.
|
|
177
189
|
node_fs_1.default.lstat(dest, (err, destStat) => {
|
|
178
190
|
if (err) {
|
|
179
191
|
if (err.code === 'ENOENT') {
|
|
@@ -203,43 +215,13 @@ function copy(src, dir, options, callback) {
|
|
|
203
215
|
* Removes files, directories, and symlinks without following symbolic links.
|
|
204
216
|
*/
|
|
205
217
|
function remove(src, callback) {
|
|
206
|
-
node_fs_1.default.
|
|
207
|
-
if (err) {
|
|
208
|
-
return callback(err);
|
|
209
|
-
}
|
|
210
|
-
if (stat.isSymbolicLink()) {
|
|
211
|
-
return node_fs_1.default.unlink(src, callback);
|
|
212
|
-
}
|
|
213
|
-
if (stat.isDirectory()) {
|
|
214
|
-
node_fs_1.default.readdir(src, (err, list) => {
|
|
215
|
-
if (err) {
|
|
216
|
-
return callback(err);
|
|
217
|
-
}
|
|
218
|
-
if (list.length === 0) {
|
|
219
|
-
return node_fs_1.default.rmdir(src, callback);
|
|
220
|
-
}
|
|
221
|
-
let reduce = list.length;
|
|
222
|
-
for (const loc of list) {
|
|
223
|
-
remove(node_path_1.default.join(src, loc), (err) => {
|
|
224
|
-
if (err) {
|
|
225
|
-
return callback(err);
|
|
226
|
-
}
|
|
227
|
-
if (--reduce === 0) {
|
|
228
|
-
node_fs_1.default.rmdir(src, callback);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
node_fs_1.default.unlink(src, callback);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
218
|
+
node_fs_1.default.rm(src, { recursive: true, force: false }, once(callback));
|
|
238
219
|
}
|
|
239
220
|
/**
|
|
240
221
|
* Removes all entries inside a directory while preserving the directory itself.
|
|
241
222
|
*/
|
|
242
223
|
function emptyDir(src, callback) {
|
|
224
|
+
callback = once(callback);
|
|
243
225
|
node_fs_1.default.readdir(src, (err, list) => {
|
|
244
226
|
if (err) {
|
|
245
227
|
return callback(err);
|
|
@@ -249,7 +231,7 @@ function emptyDir(src, callback) {
|
|
|
249
231
|
}
|
|
250
232
|
let reduce = list.length;
|
|
251
233
|
for (const loc of list) {
|
|
252
|
-
|
|
234
|
+
node_fs_1.default.rm(node_path_1.default.join(src, loc), { recursive: true, force: false }, (err) => {
|
|
253
235
|
if (err) {
|
|
254
236
|
return callback(err);
|
|
255
237
|
}
|
package/dist/suite.test.js
CHANGED
|
@@ -31,7 +31,7 @@ const distDir = node_path_1.default.resolve(__dirname);
|
|
|
31
31
|
// The runner skips itself and forwards the rest to Node's native test harness.
|
|
32
32
|
const testFiles = collectTestFiles(distDir).filter((file) => file !== __filename);
|
|
33
33
|
if (!testFiles.length) {
|
|
34
|
-
console.warn("
|
|
34
|
+
console.warn("No test files found in dist/");
|
|
35
35
|
process.exit(0);
|
|
36
36
|
}
|
|
37
37
|
const { status } = (0, node_child_process_1.spawnSync)(process.execPath, ['--test', ...testFiles], {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pwd-fs",
|
|
3
|
-
"version": "3.4
|
|
3
|
+
"version": "3.5.4",
|
|
4
4
|
"description": "Path-aware file system utilities with scoped working directories and recursive operations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"umask",
|
|
@@ -31,16 +31,11 @@
|
|
|
31
31
|
"url": "https://github.com/woodger/pwd-fs/issues"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
35
|
-
},
|
|
36
|
-
"main": "./dist/index.js",
|
|
37
|
-
"types": "./dist/index.d.ts",
|
|
38
|
-
"exports": {
|
|
39
|
-
".": {
|
|
40
|
-
"types": "./dist/index.d.ts",
|
|
41
|
-
"default": "./dist/index.js"
|
|
42
|
-
}
|
|
34
|
+
"node": ">=18"
|
|
43
35
|
},
|
|
36
|
+
"packageManager": "yarn@1.22.22",
|
|
37
|
+
"main": "dist/index.js",
|
|
38
|
+
"types": "dist/index.d.ts",
|
|
44
39
|
"files": [
|
|
45
40
|
"dist",
|
|
46
41
|
"readme.md",
|
|
@@ -52,13 +47,13 @@
|
|
|
52
47
|
"test": "node ./dist/suite.test.js"
|
|
53
48
|
},
|
|
54
49
|
"devDependencies": {
|
|
55
|
-
"@eslint/js": "
|
|
56
|
-
"@types/chance": "^1.1.
|
|
57
|
-
"@types/node": "^
|
|
50
|
+
"@eslint/js": "9.35.0",
|
|
51
|
+
"@types/chance": "^1.1.8",
|
|
52
|
+
"@types/node": "^25.6.2",
|
|
58
53
|
"chance": "^1.1.13",
|
|
59
|
-
"eslint": "
|
|
60
|
-
"globals": "^17.
|
|
61
|
-
"typescript": "^
|
|
62
|
-
"typescript-eslint": "
|
|
54
|
+
"eslint": "9.35.0",
|
|
55
|
+
"globals": "^17.6.0",
|
|
56
|
+
"typescript": "^6.0.3",
|
|
57
|
+
"typescript-eslint": "8.55.0"
|
|
63
58
|
}
|
|
64
59
|
}
|
package/readme.md
CHANGED
|
@@ -12,11 +12,11 @@ It provides:
|
|
|
12
12
|
- matching synchronous variants via `{ sync: true }`
|
|
13
13
|
- recursive helpers for copy, remove, chmod, chown, and mkdir
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Relative paths are resolved against `pfs.pwd`. Absolute paths are used as-is, so `pfs.pwd` is a convenience base path, not a sandbox.
|
|
16
16
|
|
|
17
17
|
## Why Use It
|
|
18
18
|
|
|
19
|
-
Use `pwd-fs` when you want file system operations to be
|
|
19
|
+
Use `pwd-fs` when you want file system operations to be rooted at a specific working directory without manually calling `path.resolve()` before every operation.
|
|
20
20
|
|
|
21
21
|
It is especially useful for:
|
|
22
22
|
|
|
@@ -40,6 +40,7 @@ npm install pwd-fs
|
|
|
40
40
|
- [API](#api)
|
|
41
41
|
- [`new PoweredFileSystem(pwd?)`](#new-poweredfilesystempwd)
|
|
42
42
|
- [`pfs.pwd`](#pfspwd)
|
|
43
|
+
- [`pfs.resolve(src)`](#pfsresolvesrc)
|
|
43
44
|
- [`pfs.constants`](#pfsconstants)
|
|
44
45
|
- [`PoweredFileSystem.bitmask(mode)`](#poweredfilesystembitmaskmode)
|
|
45
46
|
- [`pfs.test(src, options?)`](#pfstestsrc-options)
|
|
@@ -77,7 +78,7 @@ await pfs.mkdir('./own/project'); // recursively create the directory
|
|
|
77
78
|
|
|
78
79
|
## Common Recipes
|
|
79
80
|
|
|
80
|
-
### Work inside a
|
|
81
|
+
### Work inside a project directory
|
|
81
82
|
|
|
82
83
|
```ts
|
|
83
84
|
import { PoweredFileSystem } from 'pwd-fs';
|
|
@@ -137,7 +138,7 @@ if (await pfs.test('./tmp')) {
|
|
|
137
138
|
|
|
138
139
|
## Compatibility
|
|
139
140
|
|
|
140
|
-
- package `engines`: Node.js `>=
|
|
141
|
+
- package `engines`: Node.js `>=18`
|
|
141
142
|
- module format: CommonJS package output with TypeScript declarations
|
|
142
143
|
- platform notes:
|
|
143
144
|
- `chown()` is effectively a no-op on Windows apart from path validation
|
|
@@ -158,7 +159,7 @@ import PoweredFileSystem, { pfs, bitmask } from 'pwd-fs';
|
|
|
158
159
|
|
|
159
160
|
### `new PoweredFileSystem(pwd?)`
|
|
160
161
|
|
|
161
|
-
Creates a new instance
|
|
162
|
+
Creates a new instance with `pwd` as the base directory for relative paths.
|
|
162
163
|
|
|
163
164
|
- `pwd?: string`
|
|
164
165
|
- default: `process.cwd()`
|
|
@@ -171,7 +172,22 @@ const pfs = new PoweredFileSystem('./workspace');
|
|
|
171
172
|
|
|
172
173
|
### `pfs.pwd`
|
|
173
174
|
|
|
174
|
-
Absolute base directory used to resolve
|
|
175
|
+
Absolute base directory used to resolve relative paths.
|
|
176
|
+
|
|
177
|
+
### `pfs.resolve(src)`
|
|
178
|
+
|
|
179
|
+
Resolves `src` against `pfs.pwd`.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const pfs = new PoweredFileSystem('/workspace/project');
|
|
183
|
+
const file = pfs.resolve('./src/index.ts');
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Absolute paths are preserved:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
pfs.resolve('/tmp/outside.txt'); // '/tmp/outside.txt'
|
|
190
|
+
```
|
|
175
191
|
|
|
176
192
|
### `pfs.constants`
|
|
177
193
|
|
|
@@ -506,7 +522,8 @@ Typical cases:
|
|
|
506
522
|
- `emptyDir()` fails when the target is not a directory
|
|
507
523
|
- `write()` fails when the target path points to a directory
|
|
508
524
|
- `copy()` fails when the source does not exist
|
|
509
|
-
- `copy()`
|
|
525
|
+
- `copy()` fails when the destination already contains an entry with the same basename as the source, unless `overwrite: true` is used
|
|
526
|
+
- `copy()` fails when a directory is copied into itself
|
|
510
527
|
- `symlink()` fails when the destination already exists
|
|
511
528
|
- `mkdir()` accepts an existing directory, but fails when a path segment is a file
|
|
512
529
|
|
|
@@ -535,7 +552,8 @@ Effective permissions:
|
|
|
535
552
|
|
|
536
553
|
## Notes
|
|
537
554
|
|
|
538
|
-
- Relative paths are
|
|
555
|
+
- Relative paths are resolved against `pfs.pwd`
|
|
556
|
+
- Absolute paths are not constrained by `pfs.pwd`
|
|
539
557
|
- `stat()` returns `lstat()` data
|
|
540
558
|
- `remove()` does not follow symbolic links
|
|
541
559
|
- `append()` is kept for backward compatibility and is deprecated
|
|
@@ -562,9 +580,10 @@ Prefer native `node:fs` APIs directly when you need:
|
|
|
562
580
|
## Development
|
|
563
581
|
|
|
564
582
|
```bash
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
583
|
+
yarn install --frozen-lockfile
|
|
584
|
+
yarn lint
|
|
585
|
+
yarn build
|
|
586
|
+
yarn test
|
|
568
587
|
```
|
|
569
588
|
|
|
570
589
|
## License
|