pwd-fs 3.2.4 → 3.3.2
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/bitmask.d.ts +4 -0
- package/dist/bitmask.js +17 -0
- package/dist/bitmask.test.d.ts +1 -0
- package/dist/bitmask.test.js +29 -0
- package/dist/{src/index.d.ts → index.d.ts} +3 -0
- package/dist/{src/index.js → index.js} +3 -0
- package/dist/powered-file-system/append.d.ts +9 -0
- package/dist/powered-file-system/append.js +10 -0
- package/dist/powered-file-system/append.test.d.ts +1 -0
- package/dist/powered-file-system/append.test.js +47 -0
- package/dist/powered-file-system/chmod.d.ts +7 -0
- package/dist/powered-file-system/chmod.js +28 -0
- package/dist/powered-file-system/chmod.test.d.ts +1 -0
- package/dist/powered-file-system/chmod.test.js +71 -0
- package/dist/powered-file-system/chown.d.ts +9 -0
- package/dist/powered-file-system/chown.js +45 -0
- package/dist/powered-file-system/chown.test.d.ts +1 -0
- package/dist/powered-file-system/chown.test.js +82 -0
- package/dist/powered-file-system/copy.d.ts +8 -0
- package/dist/powered-file-system/copy.js +29 -0
- package/dist/powered-file-system/copy.test.d.ts +1 -0
- package/dist/powered-file-system/copy.test.js +82 -0
- package/dist/powered-file-system/mkdir.d.ts +8 -0
- package/dist/powered-file-system/mkdir.js +28 -0
- package/dist/powered-file-system/mkdir.test.d.ts +1 -0
- package/dist/powered-file-system/mkdir.test.js +116 -0
- package/dist/powered-file-system/read.d.ts +9 -0
- package/dist/powered-file-system/read.js +29 -0
- package/dist/powered-file-system/read.test.d.ts +1 -0
- package/dist/powered-file-system/read.test.js +75 -0
- package/dist/powered-file-system/readdir.d.ts +8 -0
- package/dist/powered-file-system/readdir.js +26 -0
- package/dist/powered-file-system/readdir.test.d.ts +1 -0
- package/dist/powered-file-system/readdir.test.js +72 -0
- package/dist/powered-file-system/remove.d.ts +7 -0
- package/dist/powered-file-system/remove.js +36 -0
- package/dist/powered-file-system/remove.test.d.ts +1 -0
- package/dist/powered-file-system/remove.test.js +78 -0
- package/dist/powered-file-system/rename.d.ts +7 -0
- package/dist/powered-file-system/rename.js +28 -0
- package/dist/powered-file-system/rename.test.d.ts +1 -0
- package/dist/powered-file-system/rename.test.js +70 -0
- package/dist/powered-file-system/stat.d.ts +7 -0
- package/dist/powered-file-system/stat.js +26 -0
- package/dist/powered-file-system/stat.test.d.ts +1 -0
- package/dist/powered-file-system/stat.test.js +79 -0
- package/dist/powered-file-system/symlink.d.ts +4 -0
- package/dist/powered-file-system/symlink.js +52 -0
- package/dist/powered-file-system/symlink.test.d.ts +1 -0
- package/dist/powered-file-system/symlink.test.js +77 -0
- package/dist/powered-file-system/test.d.ts +8 -0
- package/dist/powered-file-system/test.js +30 -0
- package/dist/powered-file-system/test.test.d.ts +1 -0
- package/dist/powered-file-system/test.test.js +76 -0
- package/dist/powered-file-system/write.d.ts +10 -0
- package/dist/powered-file-system/write.js +36 -0
- package/dist/powered-file-system/write.test.d.ts +1 -0
- package/dist/powered-file-system/write.test.js +97 -0
- package/dist/powered-file-system.d.ts +127 -0
- package/dist/powered-file-system.js +144 -0
- package/dist/powered-file-system.test.d.ts +1 -0
- package/dist/powered-file-system.test.js +21 -0
- package/dist/recurse-io-sync.d.ts +20 -0
- package/dist/{src/recurse-io-sync.js → recurse-io-sync.js} +37 -37
- package/dist/{src/recurse-io.d.ts → recurse-io.d.ts} +15 -1
- package/dist/{src/recurse-io.js → recurse-io.js} +52 -58
- package/dist/suite.test.d.ts +1 -0
- package/dist/suite.test.js +40 -0
- package/dist/test-utils.d.ts +18 -0
- package/dist/test-utils.js +72 -0
- package/package.json +31 -14
- package/readme.md +331 -246
- package/.travis.yml +0 -12
- package/appveyor.yml +0 -16
- package/dist/src/bitmask.d.ts +0 -1
- package/dist/src/bitmask.js +0 -18
- package/dist/src/powered-file-system.d.ts +0 -173
- package/dist/src/powered-file-system.js +0 -262
- package/dist/src/recurse-io-sync.d.ts +0 -5
- package/src/bitmask.ts +0 -20
- package/src/index.ts +0 -7
- package/src/powered-file-system.ts +0 -508
- package/src/recurse-io-sync.ts +0 -108
- package/src/recurse-io.ts +0 -238
- package/test/__fmock.ts +0 -45
- package/test/append.spec.ts +0 -71
- package/test/bitmask.spec.ts +0 -23
- package/test/chmod.spec.ts +0 -77
- package/test/chown.spec.ts +0 -92
- package/test/constructor.spec.ts +0 -15
- package/test/copy.spec.ts +0 -101
- package/test/mkdir.spec.ts +0 -121
- package/test/read.spec.ts +0 -91
- package/test/readdir.spec.ts +0 -86
- package/test/remove.spec.ts +0 -78
- package/test/rename.spec.ts +0 -84
- package/test/stat.spec.ts +0 -99
- package/test/symlink.spec.ts +0 -95
- package/test/test.spec.ts +0 -80
- package/test/write.spec.ts +0 -104
- package/tsconfig.json +0 -14
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.PoweredFileSystem = void 0;
|
|
21
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
22
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
23
|
+
const bitmask_1 = require("./bitmask");
|
|
24
|
+
const append_1 = require("./powered-file-system/append");
|
|
25
|
+
const chmod_1 = require("./powered-file-system/chmod");
|
|
26
|
+
const chown_1 = require("./powered-file-system/chown");
|
|
27
|
+
const copy_1 = require("./powered-file-system/copy");
|
|
28
|
+
const mkdir_1 = require("./powered-file-system/mkdir");
|
|
29
|
+
const read_1 = require("./powered-file-system/read");
|
|
30
|
+
const readdir_1 = require("./powered-file-system/readdir");
|
|
31
|
+
const remove_1 = require("./powered-file-system/remove");
|
|
32
|
+
const rename_1 = require("./powered-file-system/rename");
|
|
33
|
+
const stat_1 = require("./powered-file-system/stat");
|
|
34
|
+
const symlink_1 = require("./powered-file-system/symlink");
|
|
35
|
+
const test_1 = require("./powered-file-system/test");
|
|
36
|
+
const write_1 = require("./powered-file-system/write");
|
|
37
|
+
__exportStar(require("./bitmask"), exports);
|
|
38
|
+
/**
|
|
39
|
+
* Path-aware wrapper around Node's file system APIs.
|
|
40
|
+
*
|
|
41
|
+
* All relative paths are resolved against `pwd`, which makes the instance
|
|
42
|
+
* suitable for sandboxed or virtual working-directory workflows.
|
|
43
|
+
*/
|
|
44
|
+
class PoweredFileSystem {
|
|
45
|
+
pwd;
|
|
46
|
+
/**
|
|
47
|
+
* Access mode aliases used by `test()`.
|
|
48
|
+
*/
|
|
49
|
+
constants = {
|
|
50
|
+
e: node_fs_1.default.constants.F_OK,
|
|
51
|
+
r: node_fs_1.default.constants.R_OK,
|
|
52
|
+
w: node_fs_1.default.constants.W_OK,
|
|
53
|
+
x: node_fs_1.default.constants.X_OK
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Exposes permission mask normalization as a static helper.
|
|
57
|
+
*/
|
|
58
|
+
static bitmask = bitmask_1.bitmask;
|
|
59
|
+
/**
|
|
60
|
+
* @param pwd Base directory used to resolve all relative paths.
|
|
61
|
+
*/
|
|
62
|
+
constructor(pwd) {
|
|
63
|
+
this.pwd = pwd ? node_path_1.default.resolve(pwd) : process.cwd();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Checks whether the given path is accessible with the requested mode.
|
|
67
|
+
*/
|
|
68
|
+
test(src, options) {
|
|
69
|
+
return test_1.test.call(this, src, options);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns `lstat` information for a path.
|
|
73
|
+
*/
|
|
74
|
+
stat(src, options) {
|
|
75
|
+
return stat_1.stat.call(this, src, options);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Applies a mode recursively to a file or directory tree.
|
|
79
|
+
*/
|
|
80
|
+
chmod(src, mode, options) {
|
|
81
|
+
return chmod_1.chmod.call(this, src, mode, options);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Applies ownership recursively to a file or directory tree.
|
|
85
|
+
*/
|
|
86
|
+
chown(src, options) {
|
|
87
|
+
return chown_1.chown.call(this, src, options);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Creates a symbolic link from `dest` to `src`.
|
|
91
|
+
*/
|
|
92
|
+
symlink(src, dest, options) {
|
|
93
|
+
return symlink_1.symlink.call(this, src, dest, options);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Copies `src` into the destination directory.
|
|
97
|
+
*/
|
|
98
|
+
copy(src, dest, options) {
|
|
99
|
+
return copy_1.copy.call(this, src, dest, options);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Renames or moves a file system node.
|
|
103
|
+
*/
|
|
104
|
+
rename(src, dest, options) {
|
|
105
|
+
return rename_1.rename.call(this, src, dest, options);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Removes a file system node recursively.
|
|
109
|
+
*/
|
|
110
|
+
remove(src, options) {
|
|
111
|
+
return remove_1.remove.call(this, src, options);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Reads a file relative to the current instance root.
|
|
115
|
+
*/
|
|
116
|
+
read(src, options) {
|
|
117
|
+
return read_1.read.call(this, src, options);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Writes a file and applies the resulting permissions explicitly.
|
|
121
|
+
*/
|
|
122
|
+
write(src, data, options) {
|
|
123
|
+
return write_1.write.call(this, src, data, options);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @deprecated Use `write(..., { flag: 'a' })` instead.
|
|
127
|
+
*/
|
|
128
|
+
append(src, data, options) {
|
|
129
|
+
return append_1.append.call(this, src, data, options);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Lists directory entries relative to the current instance root.
|
|
133
|
+
*/
|
|
134
|
+
readdir(dir, options) {
|
|
135
|
+
return readdir_1.readdir.call(this, dir, options);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Creates a directory tree relative to the current instance root.
|
|
139
|
+
*/
|
|
140
|
+
mkdir(dir, options) {
|
|
141
|
+
return mkdir_1.mkdir.call(this, dir, options);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.PoweredFileSystem = PoweredFileSystem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
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_test_1 = require("node:test");
|
|
8
|
+
const index_1 = require("./index");
|
|
9
|
+
/**
|
|
10
|
+
* Verifies constructor path resolution semantics for the main API surface.
|
|
11
|
+
*/
|
|
12
|
+
(0, node_test_1.describe)('#constructor: new PoweredFileSystem(pwd?)', () => {
|
|
13
|
+
(0, node_test_1.it)('Positive: An empty path must match the context of the cwd', () => {
|
|
14
|
+
const { pwd } = new index_1.PoweredFileSystem();
|
|
15
|
+
(0, node_assert_1.default)(pwd === process.cwd());
|
|
16
|
+
});
|
|
17
|
+
(0, node_test_1.it)('Positive: Absolute path must match the context of the pwd', () => {
|
|
18
|
+
const { pwd } = new index_1.PoweredFileSystem(__dirname);
|
|
19
|
+
(0, node_assert_1.default)(pwd === __dirname);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous counterpart of the recursive chmod implementation.
|
|
3
|
+
*/
|
|
4
|
+
export declare function chmodSync(src: string, mode: number): void;
|
|
5
|
+
/**
|
|
6
|
+
* Synchronous counterpart of the recursive chown implementation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function chownSync(src: string, uid: number, gid: number): void;
|
|
9
|
+
/**
|
|
10
|
+
* Synchronously copies a file system node into the target directory.
|
|
11
|
+
*/
|
|
12
|
+
export declare function copySync(src: string, dir: string, umask: number): void;
|
|
13
|
+
/**
|
|
14
|
+
* Synchronously removes files, directories, and symlinks without following links.
|
|
15
|
+
*/
|
|
16
|
+
export declare function removeSync(src: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Synchronously creates a directory tree using permissions derived from umask.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mkdirSync(dir: string, umask: number): void;
|
|
@@ -3,21 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.chmodSync = chmodSync;
|
|
7
|
+
exports.chownSync = chownSync;
|
|
8
|
+
exports.copySync = copySync;
|
|
9
|
+
exports.removeSync = removeSync;
|
|
10
|
+
exports.mkdirSync = mkdirSync;
|
|
7
11
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Synchronous counterpart of the recursive chmod implementation.
|
|
15
|
+
*/
|
|
10
16
|
function chmodSync(src, mode) {
|
|
11
17
|
const stats = node_fs_1.default.statSync(src);
|
|
12
18
|
if (stats.isDirectory()) {
|
|
13
19
|
const list = node_fs_1.default.readdirSync(src);
|
|
14
20
|
for (const loc of list) {
|
|
15
|
-
chmodSync(
|
|
21
|
+
chmodSync(node_path_1.default.join(src, loc), mode);
|
|
16
22
|
}
|
|
17
23
|
}
|
|
18
24
|
node_fs_1.default.chmodSync(src, mode);
|
|
19
25
|
}
|
|
20
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Synchronous counterpart of the recursive chown implementation.
|
|
28
|
+
*/
|
|
21
29
|
function chownSync(src, uid, gid) {
|
|
22
30
|
const stats = node_fs_1.default.statSync(src);
|
|
23
31
|
if (uid === 0) {
|
|
@@ -29,38 +37,46 @@ function chownSync(src, uid, gid) {
|
|
|
29
37
|
if (stats.isDirectory()) {
|
|
30
38
|
const list = node_fs_1.default.readdirSync(src);
|
|
31
39
|
for (const loc of list) {
|
|
32
|
-
chownSync(
|
|
40
|
+
chownSync(node_path_1.default.join(src, loc), uid, gid);
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
43
|
node_fs_1.default.chownSync(src, uid, gid);
|
|
36
44
|
}
|
|
37
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Synchronously copies a file system node into the target directory.
|
|
47
|
+
*/
|
|
38
48
|
function copySync(src, dir, umask) {
|
|
39
49
|
const stat = node_fs_1.default.statSync(src);
|
|
40
50
|
if (stat.isDirectory()) {
|
|
41
51
|
const list = node_fs_1.default.readdirSync(src);
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
dir
|
|
46
|
-
node_fs_1.default.mkdirSync(dir, mode);
|
|
52
|
+
const loc = node_path_1.default.basename(src);
|
|
53
|
+
const mode = 0o777 & ~umask;
|
|
54
|
+
dir = node_path_1.default.join(dir, loc);
|
|
55
|
+
node_fs_1.default.mkdirSync(dir, { mode });
|
|
47
56
|
for (const loc of list) {
|
|
48
|
-
copySync(
|
|
57
|
+
copySync(node_path_1.default.join(src, loc), dir, umask);
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
else {
|
|
52
61
|
const loc = node_path_1.default.basename(src);
|
|
53
|
-
const use =
|
|
62
|
+
const use = node_path_1.default.join(dir, loc);
|
|
54
63
|
node_fs_1.default.copyFileSync(src, use);
|
|
64
|
+
node_fs_1.default.chmodSync(use, 0o666 & ~umask);
|
|
55
65
|
}
|
|
56
66
|
}
|
|
57
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Synchronously removes files, directories, and symlinks without following links.
|
|
69
|
+
*/
|
|
58
70
|
function removeSync(src) {
|
|
59
|
-
const stats = node_fs_1.default.
|
|
71
|
+
const stats = node_fs_1.default.lstatSync(src);
|
|
72
|
+
if (stats.isSymbolicLink()) {
|
|
73
|
+
node_fs_1.default.unlinkSync(src);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
60
76
|
if (stats.isDirectory()) {
|
|
61
77
|
const list = node_fs_1.default.readdirSync(src);
|
|
62
78
|
for (const loc of list) {
|
|
63
|
-
removeSync(
|
|
79
|
+
removeSync(node_path_1.default.join(src, loc));
|
|
64
80
|
}
|
|
65
81
|
node_fs_1.default.rmdirSync(src);
|
|
66
82
|
}
|
|
@@ -68,26 +84,10 @@ function removeSync(src) {
|
|
|
68
84
|
node_fs_1.default.unlinkSync(src);
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Synchronously creates a directory tree using permissions derived from umask.
|
|
89
|
+
*/
|
|
72
90
|
function mkdirSync(dir, umask) {
|
|
73
|
-
const mode = 0o777
|
|
74
|
-
|
|
75
|
-
let use = '';
|
|
76
|
-
if (dir.indexOf(cwd) === 0) {
|
|
77
|
-
use = cwd;
|
|
78
|
-
dir = dir.substring(cwd.length);
|
|
79
|
-
}
|
|
80
|
-
const ways = dir.split(sep).slice(1);
|
|
81
|
-
for (const loc of ways) {
|
|
82
|
-
use += `${sep}${loc}`;
|
|
83
|
-
try {
|
|
84
|
-
node_fs_1.default.mkdirSync(use, { mode });
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
if (err.errno !== -17) {
|
|
88
|
-
throw err;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
91
|
+
const mode = 0o777 & ~umask;
|
|
92
|
+
node_fs_1.default.mkdirSync(dir, { recursive: true, mode });
|
|
92
93
|
}
|
|
93
|
-
exports.mkdirSync = mkdirSync;
|
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { NoParamCallback } from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* Applies chmod depth-first so directories are updated after their contents.
|
|
4
|
+
*/
|
|
3
5
|
export declare function chmod(src: string, mode: number, callback: NoParamCallback): void;
|
|
6
|
+
/**
|
|
7
|
+
* Applies ownership recursively while preserving current values when uid/gid are omitted.
|
|
8
|
+
*/
|
|
4
9
|
export declare function chown(src: string, uid: number, gid: number, callback: NoParamCallback): void;
|
|
10
|
+
/**
|
|
11
|
+
* Copies a file system node into the target directory, creating directories as needed.
|
|
12
|
+
*/
|
|
5
13
|
export declare function copy(src: string, dir: string, umask: number, callback: NoParamCallback): void;
|
|
14
|
+
/**
|
|
15
|
+
* Removes files, directories, and symlinks without following symbolic links.
|
|
16
|
+
*/
|
|
6
17
|
export declare function remove(src: string, callback: NoParamCallback): void;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a directory tree with the permissions derived from the provided umask.
|
|
20
|
+
*/
|
|
7
21
|
export declare function mkdir(dir: string, umask: number, callback: NoParamCallback): void;
|
|
@@ -3,16 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.chmod = chmod;
|
|
7
|
+
exports.chown = chown;
|
|
8
|
+
exports.copy = copy;
|
|
9
|
+
exports.remove = remove;
|
|
10
|
+
exports.mkdir = mkdir;
|
|
7
11
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Applies chmod depth-first so directories are updated after their contents.
|
|
15
|
+
*/
|
|
10
16
|
function chmod(src, mode, callback) {
|
|
11
17
|
let reduce = 0;
|
|
12
18
|
node_fs_1.default.stat(src, (err, stats) => {
|
|
13
|
-
if (err)
|
|
19
|
+
if (err)
|
|
14
20
|
return callback(err);
|
|
15
|
-
}
|
|
16
21
|
if (stats.isDirectory()) {
|
|
17
22
|
node_fs_1.default.readdir(src, (err, list) => {
|
|
18
23
|
if (err) {
|
|
@@ -21,9 +26,9 @@ function chmod(src, mode, callback) {
|
|
|
21
26
|
if (list.length === 0) {
|
|
22
27
|
return node_fs_1.default.chmod(src, mode, callback);
|
|
23
28
|
}
|
|
24
|
-
reduce
|
|
29
|
+
reduce = list.length;
|
|
25
30
|
for (const loc of list) {
|
|
26
|
-
chmod(
|
|
31
|
+
chmod(node_path_1.default.join(src, loc), mode, (err) => {
|
|
27
32
|
if (err) {
|
|
28
33
|
return callback(err);
|
|
29
34
|
}
|
|
@@ -39,7 +44,9 @@ function chmod(src, mode, callback) {
|
|
|
39
44
|
}
|
|
40
45
|
});
|
|
41
46
|
}
|
|
42
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Applies ownership recursively while preserving current values when uid/gid are omitted.
|
|
49
|
+
*/
|
|
43
50
|
function chown(src, uid, gid, callback) {
|
|
44
51
|
let reduce = 0;
|
|
45
52
|
node_fs_1.default.stat(src, (err, stats) => {
|
|
@@ -60,9 +67,9 @@ function chown(src, uid, gid, callback) {
|
|
|
60
67
|
if (list.length === 0) {
|
|
61
68
|
return node_fs_1.default.chown(src, uid, gid, callback);
|
|
62
69
|
}
|
|
63
|
-
reduce
|
|
70
|
+
reduce = list.length;
|
|
64
71
|
for (const loc of list) {
|
|
65
|
-
chown(
|
|
72
|
+
chown(node_path_1.default.join(src, loc), uid, gid, (err) => {
|
|
66
73
|
if (err) {
|
|
67
74
|
return callback(err);
|
|
68
75
|
}
|
|
@@ -78,9 +85,10 @@ function chown(src, uid, gid, callback) {
|
|
|
78
85
|
}
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Copies a file system node into the target directory, creating directories as needed.
|
|
90
|
+
*/
|
|
82
91
|
function copy(src, dir, umask, callback) {
|
|
83
|
-
let reduce = 0;
|
|
84
92
|
node_fs_1.default.stat(src, (err, stat) => {
|
|
85
93
|
if (err) {
|
|
86
94
|
return callback(err);
|
|
@@ -90,20 +98,22 @@ function copy(src, dir, umask, callback) {
|
|
|
90
98
|
if (err) {
|
|
91
99
|
return callback(err);
|
|
92
100
|
}
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
dir = `${dir}${sep}${loc}`;
|
|
98
|
-
node_fs_1.default.mkdir(dir, { mode }, (err) => {
|
|
101
|
+
const loc = node_path_1.default.basename(src);
|
|
102
|
+
const destDir = node_path_1.default.join(dir, loc);
|
|
103
|
+
const mode = 0o777 & ~umask;
|
|
104
|
+
node_fs_1.default.mkdir(destDir, { mode }, (err) => {
|
|
99
105
|
if (err) {
|
|
106
|
+
if (err.code === 'EEXIST') {
|
|
107
|
+
err = new Error(`Target already exists: ${destDir}`);
|
|
108
|
+
}
|
|
100
109
|
return callback(err);
|
|
101
110
|
}
|
|
102
|
-
if (
|
|
111
|
+
if (list.length === 0) {
|
|
103
112
|
return callback(null);
|
|
104
113
|
}
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
let reduce = list.length;
|
|
115
|
+
for (const item of list) {
|
|
116
|
+
copy(node_path_1.default.join(src, item), destDir, umask, (err) => {
|
|
107
117
|
if (err) {
|
|
108
118
|
return callback(err);
|
|
109
119
|
}
|
|
@@ -116,38 +126,42 @@ function copy(src, dir, umask, callback) {
|
|
|
116
126
|
});
|
|
117
127
|
}
|
|
118
128
|
else {
|
|
119
|
-
const mode = 0o666 - umask;
|
|
120
129
|
const loc = node_path_1.default.basename(src);
|
|
130
|
+
const dest = node_path_1.default.join(dir, loc);
|
|
131
|
+
const mode = 0o666 & ~umask;
|
|
121
132
|
const readStream = node_fs_1.default.createReadStream(src);
|
|
122
|
-
const writeStream = node_fs_1.default.createWriteStream(
|
|
123
|
-
mode
|
|
124
|
-
});
|
|
133
|
+
const writeStream = node_fs_1.default.createWriteStream(dest, { mode });
|
|
125
134
|
readStream.on('error', callback);
|
|
126
135
|
writeStream.on('error', callback);
|
|
127
136
|
writeStream.on('close', () => {
|
|
128
|
-
callback
|
|
137
|
+
node_fs_1.default.chmod(dest, mode, callback);
|
|
129
138
|
});
|
|
130
139
|
readStream.pipe(writeStream);
|
|
131
140
|
}
|
|
132
141
|
});
|
|
133
142
|
}
|
|
134
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Removes files, directories, and symlinks without following symbolic links.
|
|
145
|
+
*/
|
|
135
146
|
function remove(src, callback) {
|
|
136
|
-
node_fs_1.default.
|
|
147
|
+
node_fs_1.default.lstat(src, (err, stat) => {
|
|
137
148
|
if (err) {
|
|
138
149
|
return callback(err);
|
|
139
150
|
}
|
|
151
|
+
if (stat.isSymbolicLink()) {
|
|
152
|
+
return node_fs_1.default.unlink(src, callback);
|
|
153
|
+
}
|
|
140
154
|
if (stat.isDirectory()) {
|
|
141
155
|
node_fs_1.default.readdir(src, (err, list) => {
|
|
142
156
|
if (err) {
|
|
143
157
|
return callback(err);
|
|
144
158
|
}
|
|
145
|
-
|
|
146
|
-
if (reduce === 0) {
|
|
159
|
+
if (list.length === 0) {
|
|
147
160
|
return node_fs_1.default.rmdir(src, callback);
|
|
148
161
|
}
|
|
162
|
+
let reduce = list.length;
|
|
149
163
|
for (const loc of list) {
|
|
150
|
-
remove(
|
|
164
|
+
remove(node_path_1.default.join(src, loc), (err) => {
|
|
151
165
|
if (err) {
|
|
152
166
|
return callback(err);
|
|
153
167
|
}
|
|
@@ -163,35 +177,15 @@ function remove(src, callback) {
|
|
|
163
177
|
}
|
|
164
178
|
});
|
|
165
179
|
}
|
|
166
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Creates a directory tree with the permissions derived from the provided umask.
|
|
182
|
+
*/
|
|
167
183
|
function mkdir(dir, umask, callback) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const sequence = function* (dir, files, mode) {
|
|
173
|
-
const iter = yield;
|
|
174
|
-
for (const item of files) {
|
|
175
|
-
dir += `${sep}${item}`;
|
|
176
|
-
node_fs_1.default.mkdir(dir, { mode }, (err) => {
|
|
177
|
-
if (err && err.errno !== -17) {
|
|
178
|
-
return callback(err);
|
|
179
|
-
}
|
|
180
|
-
iter.next();
|
|
181
|
-
});
|
|
182
|
-
yield;
|
|
184
|
+
const mode = 0o777 & ~umask;
|
|
185
|
+
node_fs_1.default.mkdir(dir, { recursive: true, mode }, (err) => {
|
|
186
|
+
if (err && err.code !== 'EEXIST') {
|
|
187
|
+
return callback(err);
|
|
183
188
|
}
|
|
184
189
|
callback(null);
|
|
185
|
-
};
|
|
186
|
-
let use = '';
|
|
187
|
-
if (dir.indexOf(cwd) === 0) {
|
|
188
|
-
use = cwd;
|
|
189
|
-
dir = dir.substring(cwd.length);
|
|
190
|
-
}
|
|
191
|
-
const files = dir.split(sep);
|
|
192
|
-
const mode = 0o777 - umask;
|
|
193
|
-
const iter = sequence(use, files, mode);
|
|
194
|
-
iter.next();
|
|
195
|
-
iter.next(iter);
|
|
190
|
+
});
|
|
196
191
|
}
|
|
197
|
-
exports.mkdir = mkdir;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
/**
|
|
10
|
+
* Recursively collects compiled test files emitted into `dist/`.
|
|
11
|
+
*/
|
|
12
|
+
function collectTestFiles(dir) {
|
|
13
|
+
let files = [];
|
|
14
|
+
for (const entry of node_fs_1.default.readdirSync(dir)) {
|
|
15
|
+
const fullPath = node_path_1.default.join(dir, entry);
|
|
16
|
+
const stat = node_fs_1.default.statSync(fullPath);
|
|
17
|
+
if (stat.isDirectory()) {
|
|
18
|
+
if (entry === 'src' || entry === 'test') {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
files = files.concat(collectTestFiles(fullPath));
|
|
22
|
+
}
|
|
23
|
+
else if (/\.test\.js$/.test(entry)) {
|
|
24
|
+
files.push(fullPath);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return files;
|
|
28
|
+
}
|
|
29
|
+
// The compiled output directory is the root for the test runner.
|
|
30
|
+
const distDir = node_path_1.default.resolve(__dirname);
|
|
31
|
+
// The runner skips itself and forwards the rest to Node's native test harness.
|
|
32
|
+
const testFiles = collectTestFiles(distDir).filter((file) => file !== __filename);
|
|
33
|
+
if (!testFiles.length) {
|
|
34
|
+
console.warn("⚠️ No test files found in dist/");
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
const { status } = (0, node_child_process_1.spawnSync)(process.execPath, ['--test', ...testFiles], {
|
|
38
|
+
stdio: 'inherit'
|
|
39
|
+
});
|
|
40
|
+
process.exitCode = status ?? 1;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight in-memory-like description of a temporary file system tree.
|
|
3
|
+
*/
|
|
4
|
+
export interface Iframe {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates an isolated temporary directory for a single test case.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createTmpDir(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Materializes a test fixture tree on disk from a declarative frame description.
|
|
13
|
+
*/
|
|
14
|
+
export declare function fmock(frame: Iframe): void;
|
|
15
|
+
/**
|
|
16
|
+
* Removes the temporary fixture tree while resetting restrictive permissions first.
|
|
17
|
+
*/
|
|
18
|
+
export declare function restore(tmpDir: string): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
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.createTmpDir = createTmpDir;
|
|
7
|
+
exports.fmock = fmock;
|
|
8
|
+
exports.restore = restore;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
/**
|
|
13
|
+
* Creates an isolated temporary directory for a single test case.
|
|
14
|
+
*/
|
|
15
|
+
function createTmpDir() {
|
|
16
|
+
return node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'pwd-fs-'));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Materializes a test fixture tree on disk from a declarative frame description.
|
|
20
|
+
*/
|
|
21
|
+
function fmock(frame) {
|
|
22
|
+
for (const src of Object.keys(frame)) {
|
|
23
|
+
const { dir } = node_path_1.default.parse(src);
|
|
24
|
+
const value = frame[src];
|
|
25
|
+
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
26
|
+
if (value.type === 'directory') {
|
|
27
|
+
node_fs_1.default.mkdirSync(src);
|
|
28
|
+
}
|
|
29
|
+
if (value.type === 'file') {
|
|
30
|
+
node_fs_1.default.writeFileSync(src, value.data);
|
|
31
|
+
}
|
|
32
|
+
if (value.type === 'symlink') {
|
|
33
|
+
let type;
|
|
34
|
+
if (process.platform === 'win32') {
|
|
35
|
+
const stats = node_fs_1.default.lstatSync(value.target);
|
|
36
|
+
type = stats.isDirectory() ? 'junction' : 'file';
|
|
37
|
+
}
|
|
38
|
+
node_fs_1.default.symlinkSync(value.target, src, type);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Removes the temporary fixture tree while resetting restrictive permissions first.
|
|
44
|
+
*/
|
|
45
|
+
function restore(tmpDir) {
|
|
46
|
+
const removeRecursive = (src) => {
|
|
47
|
+
if (node_fs_1.default.existsSync(src)) {
|
|
48
|
+
const stats = node_fs_1.default.lstatSync(src);
|
|
49
|
+
if (stats.isSymbolicLink()) {
|
|
50
|
+
node_fs_1.default.unlinkSync(src);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
node_fs_1.default.chmodSync(src, 0o755);
|
|
54
|
+
node_fs_1.default.readdirSync(src).forEach((item) => {
|
|
55
|
+
const curl = node_path_1.default.join(src, item);
|
|
56
|
+
const stats = node_fs_1.default.lstatSync(curl);
|
|
57
|
+
if (stats.isSymbolicLink()) {
|
|
58
|
+
node_fs_1.default.unlinkSync(curl);
|
|
59
|
+
}
|
|
60
|
+
else if (stats.isDirectory()) {
|
|
61
|
+
removeRecursive(curl);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
node_fs_1.default.chmodSync(curl, 0o666);
|
|
65
|
+
node_fs_1.default.unlinkSync(curl);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
node_fs_1.default.rmdirSync(src);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
removeRecursive(tmpDir);
|
|
72
|
+
}
|