pwd-fs 3.3.0 → 3.3.5

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.
Files changed (104) hide show
  1. package/dist/bitmask.d.ts +4 -0
  2. package/dist/{src/bitmask.js → bitmask.js} +3 -1
  3. package/dist/bitmask.test.d.ts +1 -0
  4. package/dist/bitmask.test.js +29 -0
  5. package/dist/{src/index.d.ts → index.d.ts} +3 -0
  6. package/dist/{src/index.js → index.js} +3 -1
  7. package/dist/powered-file-system/append.d.ts +9 -0
  8. package/dist/powered-file-system/append.js +10 -0
  9. package/dist/powered-file-system/append.test.d.ts +1 -0
  10. package/dist/powered-file-system/append.test.js +47 -0
  11. package/dist/powered-file-system/chmod.d.ts +7 -0
  12. package/dist/powered-file-system/chmod.js +28 -0
  13. package/dist/powered-file-system/chmod.test.d.ts +1 -0
  14. package/dist/powered-file-system/chmod.test.js +71 -0
  15. package/dist/powered-file-system/chown.d.ts +9 -0
  16. package/dist/powered-file-system/chown.js +45 -0
  17. package/dist/powered-file-system/chown.test.d.ts +1 -0
  18. package/dist/powered-file-system/chown.test.js +82 -0
  19. package/dist/powered-file-system/copy.d.ts +8 -0
  20. package/dist/powered-file-system/copy.js +29 -0
  21. package/dist/powered-file-system/copy.test.d.ts +1 -0
  22. package/dist/powered-file-system/copy.test.js +82 -0
  23. package/dist/powered-file-system/mkdir.d.ts +8 -0
  24. package/dist/powered-file-system/mkdir.js +28 -0
  25. package/dist/powered-file-system/mkdir.test.d.ts +1 -0
  26. package/dist/powered-file-system/mkdir.test.js +116 -0
  27. package/dist/powered-file-system/read.d.ts +9 -0
  28. package/dist/powered-file-system/read.js +29 -0
  29. package/dist/powered-file-system/read.test.d.ts +1 -0
  30. package/dist/powered-file-system/read.test.js +75 -0
  31. package/dist/powered-file-system/readdir.d.ts +8 -0
  32. package/dist/powered-file-system/readdir.js +26 -0
  33. package/dist/powered-file-system/readdir.test.d.ts +1 -0
  34. package/dist/powered-file-system/readdir.test.js +72 -0
  35. package/dist/powered-file-system/remove.d.ts +7 -0
  36. package/dist/powered-file-system/remove.js +36 -0
  37. package/dist/powered-file-system/remove.test.d.ts +1 -0
  38. package/dist/powered-file-system/remove.test.js +78 -0
  39. package/dist/powered-file-system/rename.d.ts +7 -0
  40. package/dist/powered-file-system/rename.js +28 -0
  41. package/dist/powered-file-system/rename.test.d.ts +1 -0
  42. package/dist/powered-file-system/rename.test.js +70 -0
  43. package/dist/powered-file-system/stat.d.ts +7 -0
  44. package/dist/powered-file-system/stat.js +26 -0
  45. package/dist/powered-file-system/stat.test.d.ts +1 -0
  46. package/dist/powered-file-system/stat.test.js +79 -0
  47. package/dist/powered-file-system/symlink.d.ts +4 -0
  48. package/dist/powered-file-system/symlink.js +52 -0
  49. package/dist/powered-file-system/symlink.test.d.ts +1 -0
  50. package/dist/powered-file-system/symlink.test.js +77 -0
  51. package/dist/powered-file-system/test.d.ts +8 -0
  52. package/dist/powered-file-system/test.js +30 -0
  53. package/dist/powered-file-system/test.test.d.ts +1 -0
  54. package/dist/powered-file-system/test.test.js +76 -0
  55. package/dist/powered-file-system/write.d.ts +10 -0
  56. package/dist/powered-file-system/write.js +36 -0
  57. package/dist/powered-file-system/write.test.d.ts +1 -0
  58. package/dist/powered-file-system/write.test.js +97 -0
  59. package/dist/{src/powered-file-system.d.ts → powered-file-system.d.ts} +57 -4
  60. package/dist/powered-file-system.js +144 -0
  61. package/dist/powered-file-system.test.d.ts +1 -0
  62. package/dist/powered-file-system.test.js +21 -0
  63. package/dist/recurse-io-sync.d.ts +20 -0
  64. package/dist/{src/recurse-io-sync.js → recurse-io-sync.js} +25 -23
  65. package/dist/{src/recurse-io.d.ts → recurse-io.d.ts} +15 -0
  66. package/dist/{src/recurse-io.js → recurse-io.js} +30 -28
  67. package/dist/suite.test.d.ts +1 -0
  68. package/dist/suite.test.js +40 -0
  69. package/dist/test-utils.d.ts +18 -0
  70. package/dist/test-utils.js +72 -0
  71. package/package.json +27 -10
  72. package/readme.md +331 -246
  73. package/.travis.yml +0 -12
  74. package/appveyor.yml +0 -16
  75. package/dist/src/bitmask.d.ts +0 -1
  76. package/dist/src/bitmask.js.map +0 -1
  77. package/dist/src/index.js.map +0 -1
  78. package/dist/src/powered-file-system.js +0 -252
  79. package/dist/src/powered-file-system.js.map +0 -1
  80. package/dist/src/recurse-io-sync.d.ts +0 -5
  81. package/dist/src/recurse-io-sync.js.map +0 -1
  82. package/dist/src/recurse-io.js.map +0 -1
  83. package/src/bitmask.ts +0 -13
  84. package/src/index.ts +0 -5
  85. package/src/powered-file-system.ts +0 -369
  86. package/src/recurse-io-sync.ts +0 -105
  87. package/src/recurse-io.ts +0 -221
  88. package/test/__fmock.ts +0 -45
  89. package/test/append.spec.ts +0 -45
  90. package/test/bitmask.spec.ts +0 -23
  91. package/test/chmod.spec.ts +0 -77
  92. package/test/chown.spec.ts +0 -92
  93. package/test/constructor.spec.ts +0 -15
  94. package/test/copy.spec.ts +0 -101
  95. package/test/mkdir.spec.ts +0 -121
  96. package/test/read.spec.ts +0 -91
  97. package/test/readdir.spec.ts +0 -86
  98. package/test/remove.spec.ts +0 -78
  99. package/test/rename.spec.ts +0 -84
  100. package/test/stat.spec.ts +0 -99
  101. package/test/symlink.spec.ts +0 -95
  102. package/test/test.spec.ts +0 -80
  103. package/test/write.spec.ts +0 -104
  104. package/tsconfig.json +0 -17
@@ -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;
@@ -10,6 +10,9 @@ exports.removeSync = removeSync;
10
10
  exports.mkdirSync = mkdirSync;
11
11
  const node_fs_1 = __importDefault(require("node:fs"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
+ /**
14
+ * Synchronous counterpart of the recursive chmod implementation.
15
+ */
13
16
  function chmodSync(src, mode) {
14
17
  const stats = node_fs_1.default.statSync(src);
15
18
  if (stats.isDirectory()) {
@@ -20,6 +23,9 @@ function chmodSync(src, mode) {
20
23
  }
21
24
  node_fs_1.default.chmodSync(src, mode);
22
25
  }
26
+ /**
27
+ * Synchronous counterpart of the recursive chown implementation.
28
+ */
23
29
  function chownSync(src, uid, gid) {
24
30
  const stats = node_fs_1.default.statSync(src);
25
31
  if (uid === 0) {
@@ -36,14 +42,17 @@ function chownSync(src, uid, gid) {
36
42
  }
37
43
  node_fs_1.default.chownSync(src, uid, gid);
38
44
  }
45
+ /**
46
+ * Synchronously copies a file system node into the target directory.
47
+ */
39
48
  function copySync(src, dir, umask) {
40
49
  const stat = node_fs_1.default.statSync(src);
41
50
  if (stat.isDirectory()) {
42
51
  const list = node_fs_1.default.readdirSync(src);
43
52
  const loc = node_path_1.default.basename(src);
44
- const mode = 0o777 - umask;
53
+ const mode = 0o777 & ~umask;
45
54
  dir = node_path_1.default.join(dir, loc);
46
- node_fs_1.default.mkdirSync(dir, mode);
55
+ node_fs_1.default.mkdirSync(dir, { mode });
47
56
  for (const loc of list) {
48
57
  copySync(node_path_1.default.join(src, loc), dir, umask);
49
58
  }
@@ -52,10 +61,18 @@ function copySync(src, dir, umask) {
52
61
  const loc = node_path_1.default.basename(src);
53
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
  }
67
+ /**
68
+ * Synchronously removes files, directories, and symlinks without following links.
69
+ */
57
70
  function removeSync(src) {
58
- const stats = node_fs_1.default.statSync(src);
71
+ const stats = node_fs_1.default.lstatSync(src);
72
+ if (stats.isSymbolicLink()) {
73
+ node_fs_1.default.unlinkSync(src);
74
+ return;
75
+ }
59
76
  if (stats.isDirectory()) {
60
77
  const list = node_fs_1.default.readdirSync(src);
61
78
  for (const loc of list) {
@@ -67,25 +84,10 @@ function removeSync(src) {
67
84
  node_fs_1.default.unlinkSync(src);
68
85
  }
69
86
  }
87
+ /**
88
+ * Synchronously creates a directory tree using permissions derived from umask.
89
+ */
70
90
  function mkdirSync(dir, umask) {
71
- const mode = 0o777 - umask;
72
- const cwd = process.cwd();
73
- let use = '';
74
- if (dir.indexOf(cwd) === 0) {
75
- use = cwd;
76
- dir = dir.substring(cwd.length);
77
- }
78
- const ways = dir.split(node_path_1.default.sep).slice(1);
79
- for (const loc of ways) {
80
- use = node_path_1.default.join(use, loc);
81
- try {
82
- node_fs_1.default.mkdirSync(use, { mode });
83
- }
84
- catch (err) {
85
- if (err.code !== 'EEXIST') {
86
- throw err;
87
- }
88
- }
89
- }
91
+ const mode = 0o777 & ~umask;
92
+ node_fs_1.default.mkdirSync(dir, { recursive: true, mode });
90
93
  }
91
- //# sourceMappingURL=recurse-io-sync.js.map
@@ -1,6 +1,21 @@
1
1
  import { NoParamCallback } from 'node:fs';
2
+ /**
3
+ * Applies chmod depth-first so directories are updated after their contents.
4
+ */
2
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
+ */
3
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
+ */
4
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
+ */
5
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
+ */
6
21
  export declare function mkdir(dir: string, umask: number, callback: NoParamCallback): void;
@@ -10,6 +10,9 @@ exports.remove = remove;
10
10
  exports.mkdir = mkdir;
11
11
  const node_fs_1 = __importDefault(require("node:fs"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
+ /**
14
+ * Applies chmod depth-first so directories are updated after their contents.
15
+ */
13
16
  function chmod(src, mode, callback) {
14
17
  let reduce = 0;
15
18
  node_fs_1.default.stat(src, (err, stats) => {
@@ -41,6 +44,9 @@ function chmod(src, mode, callback) {
41
44
  }
42
45
  });
43
46
  }
47
+ /**
48
+ * Applies ownership recursively while preserving current values when uid/gid are omitted.
49
+ */
44
50
  function chown(src, uid, gid, callback) {
45
51
  let reduce = 0;
46
52
  node_fs_1.default.stat(src, (err, stats) => {
@@ -79,6 +85,9 @@ function chown(src, uid, gid, callback) {
79
85
  }
80
86
  });
81
87
  }
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
92
  node_fs_1.default.stat(src, (err, stat) => {
84
93
  if (err) {
@@ -91,7 +100,7 @@ function copy(src, dir, umask, callback) {
91
100
  }
92
101
  const loc = node_path_1.default.basename(src);
93
102
  const destDir = node_path_1.default.join(dir, loc);
94
- const mode = 0o777 - umask;
103
+ const mode = 0o777 & ~umask;
95
104
  node_fs_1.default.mkdir(destDir, { mode }, (err) => {
96
105
  if (err) {
97
106
  if (err.code === 'EEXIST') {
@@ -119,21 +128,29 @@ function copy(src, dir, umask, callback) {
119
128
  else {
120
129
  const loc = node_path_1.default.basename(src);
121
130
  const dest = node_path_1.default.join(dir, loc);
122
- const mode = 0o666 - umask;
131
+ const mode = 0o666 & ~umask;
123
132
  const readStream = node_fs_1.default.createReadStream(src);
124
133
  const writeStream = node_fs_1.default.createWriteStream(dest, { mode });
125
134
  readStream.on('error', callback);
126
135
  writeStream.on('error', callback);
127
- writeStream.on('close', () => callback(null));
136
+ writeStream.on('close', () => {
137
+ node_fs_1.default.chmod(dest, mode, callback);
138
+ });
128
139
  readStream.pipe(writeStream);
129
140
  }
130
141
  });
131
142
  }
143
+ /**
144
+ * Removes files, directories, and symlinks without following symbolic links.
145
+ */
132
146
  function remove(src, callback) {
133
- node_fs_1.default.stat(src, (err, stat) => {
147
+ node_fs_1.default.lstat(src, (err, stat) => {
134
148
  if (err) {
135
149
  return callback(err);
136
150
  }
151
+ if (stat.isSymbolicLink()) {
152
+ return node_fs_1.default.unlink(src, callback);
153
+ }
137
154
  if (stat.isDirectory()) {
138
155
  node_fs_1.default.readdir(src, (err, list) => {
139
156
  if (err) {
@@ -160,30 +177,15 @@ function remove(src, callback) {
160
177
  }
161
178
  });
162
179
  }
180
+ /**
181
+ * Creates a directory tree with the permissions derived from the provided umask.
182
+ */
163
183
  function mkdir(dir, umask, callback) {
164
- const cwd = process.cwd();
165
- if (dir === cwd) {
166
- return callback(null);
167
- }
168
- let base = '';
169
- const mode = 0o777 - umask;
170
- if (dir.startsWith(cwd)) {
171
- base = cwd;
172
- dir = dir.slice(cwd.length);
173
- }
174
- const parts = dir.split(node_path_1.default.sep).filter(Boolean);
175
- function next(index) {
176
- if (index >= parts.length) {
177
- return callback(null);
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);
178
188
  }
179
- base = node_path_1.default.join(base, parts[index]);
180
- node_fs_1.default.mkdir(base, { mode }, (err) => {
181
- if (err && err.code !== 'EEXIST') {
182
- return callback(err);
183
- }
184
- next(index + 1);
185
- });
186
- }
187
- next(0);
189
+ callback(null);
190
+ });
188
191
  }
189
- //# sourceMappingURL=recurse-io.js.map
@@ -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
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pwd-fs",
3
- "version": "3.3.0",
4
- "description": "Extend the file system the capabilities of declaring the present working directory and recursive execution",
3
+ "version": "3.3.5",
4
+ "description": "Path-aware file system utilities with scoped working directories and recursive operations",
5
5
  "keywords": [
6
6
  "umask",
7
7
  "test",
@@ -24,24 +24,41 @@
24
24
  "license": "MIT",
25
25
  "repository": {
26
26
  "type": "git",
27
- "url": "git@github.com:woodger/pwd-fs.git"
27
+ "url": "https://github.com/woodger/pwd-fs.git"
28
+ },
29
+ "homepage": "https://github.com/woodger/pwd-fs#readme",
30
+ "bugs": {
31
+ "url": "https://github.com/woodger/pwd-fs/issues"
28
32
  },
29
33
  "engines": {
30
34
  "node": ">=13.2.0"
31
35
  },
32
- "main": "./dist/src/index.js",
33
- "types": "./dist/src/index.d.ts",
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
+ }
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "readme.md",
47
+ "LICENSE"
48
+ ],
34
49
  "scripts": {
35
50
  "build": "tsc",
36
- "test": "mocha ./dist/test"
51
+ "lint": "eslint src",
52
+ "test": "node ./dist/suite.test.js"
37
53
  },
38
54
  "devDependencies": {
55
+ "@eslint/js": "^10.0.1",
39
56
  "@types/chance": "^1.1.7",
40
- "@types/mocha": "^10.0.10",
41
57
  "@types/node": "^24.5.1",
42
58
  "chance": "^1.1.13",
43
- "expect": "^30.1.2",
44
- "mocha": "^11.7.2",
45
- "typescript": "^5.9.2"
59
+ "eslint": "^10.1.0",
60
+ "globals": "^17.4.0",
61
+ "typescript": "^5.9.2",
62
+ "typescript-eslint": "^8.57.2"
46
63
  }
47
64
  }