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,79 @@
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
+ * Ensures `stat()` preserves file type reporting for files, directories, and symlinks.
14
+ */
15
+ (0, node_test_1.describe)('stat(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, 'digest')]: { type: 'directory' },
26
+ [node_path_1.default.join(tmpDir, 'flexapp')]: {
27
+ type: 'symlink',
28
+ target: node_path_1.default.join(tmpDir, 'tings.txt')
29
+ }
30
+ });
31
+ });
32
+ (0, node_test_1.afterEach)(() => {
33
+ (0, test_utils_1.restore)(tmpDir);
34
+ });
35
+ (0, node_test_1.it)('Positive: Must return information a file', async () => {
36
+ const stats = await index_1.pfs.stat(node_path_1.default.join(tmpDir, 'tings.txt'));
37
+ (0, node_assert_1.default)(stats.isFile());
38
+ });
39
+ (0, node_test_1.it)('Positive: Must return information a directory', async () => {
40
+ const stats = await index_1.pfs.stat(node_path_1.default.join(tmpDir, 'digest'));
41
+ (0, node_assert_1.default)(stats.isDirectory());
42
+ });
43
+ (0, node_test_1.it)('Positive: Must return information a symlink', async () => {
44
+ const stats = await index_1.pfs.stat(node_path_1.default.join(tmpDir, 'flexapp'));
45
+ (0, node_assert_1.default)(stats.isSymbolicLink());
46
+ });
47
+ (0, node_test_1.it)('Negative: Throw if not exists resource', async () => {
48
+ const guid = chance.guid();
49
+ await node_assert_1.default.rejects(async () => {
50
+ await index_1.pfs.stat(node_path_1.default.join(tmpDir, guid));
51
+ });
52
+ });
53
+ (0, node_test_1.it)('[sync] Positive: Must return information a file', () => {
54
+ const stats = index_1.pfs.stat(node_path_1.default.join(tmpDir, 'tings.txt'), {
55
+ sync: true
56
+ });
57
+ (0, node_assert_1.default)(stats.isFile());
58
+ });
59
+ (0, node_test_1.it)('[sync] Positive: Must return information a directory in ', () => {
60
+ const stats = index_1.pfs.stat(node_path_1.default.join(tmpDir, 'digest'), {
61
+ sync: true
62
+ });
63
+ (0, node_assert_1.default)(stats.isDirectory());
64
+ });
65
+ (0, node_test_1.it)('[sync] Positive: Must return information a symlink', () => {
66
+ const stats = index_1.pfs.stat(node_path_1.default.join(tmpDir, 'flexapp'), {
67
+ sync: true
68
+ });
69
+ (0, node_assert_1.default)(stats.isSymbolicLink());
70
+ });
71
+ (0, node_test_1.it)('[sync] Negative: Throw if not exists resource', () => {
72
+ const guid = chance.guid();
73
+ node_assert_1.default.throws(() => {
74
+ index_1.pfs.stat(node_path_1.default.join(tmpDir, guid), {
75
+ sync: true
76
+ });
77
+ });
78
+ });
79
+ });
@@ -0,0 +1,4 @@
1
+ import type { PoweredFileSystem } from '../powered-file-system';
2
+ export declare function symlink<T extends boolean = false>(this: PoweredFileSystem, src: string, dest: string, options?: {
3
+ sync?: T;
4
+ }): T extends true ? void : Promise<void>;
@@ -0,0 +1,52 @@
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.symlink = symlink;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ /**
10
+ * Windows requires an explicit link type. Non-Windows platforms infer it.
11
+ */
12
+ function resolveSymlinkType(src) {
13
+ if (process.platform !== 'win32') {
14
+ return undefined;
15
+ }
16
+ const stats = node_fs_1.default.lstatSync(src);
17
+ return stats.isDirectory() ? 'junction' : 'file';
18
+ }
19
+ function symlink(src, dest, options) {
20
+ src = node_path_1.default.resolve(this.pwd, src);
21
+ dest = node_path_1.default.resolve(this.pwd, dest);
22
+ const { sync = false } = options ?? {};
23
+ if (sync) {
24
+ const type = resolveSymlinkType(src);
25
+ node_fs_1.default.symlinkSync(src, dest, type);
26
+ return undefined;
27
+ }
28
+ return new Promise((resolve, reject) => {
29
+ if (process.platform === 'win32') {
30
+ node_fs_1.default.lstat(src, (err, stats) => {
31
+ if (err) {
32
+ return reject(err);
33
+ }
34
+ const type = stats.isDirectory() ? 'junction' : 'file';
35
+ node_fs_1.default.symlink(src, dest, type, (err) => {
36
+ if (err) {
37
+ return reject(err);
38
+ }
39
+ resolve();
40
+ });
41
+ });
42
+ }
43
+ else {
44
+ node_fs_1.default.symlink(src, dest, (err) => {
45
+ if (err) {
46
+ return reject(err);
47
+ }
48
+ resolve();
49
+ });
50
+ }
51
+ });
52
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,77 @@
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
+ * Covers symlink creation for file and directory targets.
15
+ */
16
+ (0, node_test_1.describe)('symlink(src, use [, 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, 'flexapp')]: {
28
+ type: 'symlink',
29
+ target: node_path_1.default.join(tmpDir, 'tings.txt')
30
+ }
31
+ };
32
+ const counter = chance.natural({ max: 7 });
33
+ for (let i = 0; i < counter; i++) {
34
+ frame[node_path_1.default.join(tmpDir, String(i))] = { type: 'directory' };
35
+ }
36
+ (0, test_utils_1.fmock)(frame);
37
+ });
38
+ (0, node_test_1.afterEach)(() => {
39
+ (0, test_utils_1.restore)(tmpDir);
40
+ });
41
+ (0, node_test_1.it)('Positive: Must be created a symbolic link', async () => {
42
+ await index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'linkapp'));
43
+ const stat = node_fs_1.default.lstatSync(node_path_1.default.join(tmpDir, 'linkapp'));
44
+ (0, node_assert_1.default)(stat.isSymbolicLink());
45
+ });
46
+ (0, node_test_1.it)('Positive: Must be created a symbolic link for directory', async () => {
47
+ await index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'digest'), node_path_1.default.join(tmpDir, 'linkapp'));
48
+ const stat = node_fs_1.default.lstatSync(node_path_1.default.join(tmpDir, 'linkapp'));
49
+ (0, node_assert_1.default)(stat.isSymbolicLink());
50
+ });
51
+ (0, node_test_1.it)('Negative: Throw if destination already exists', async () => {
52
+ await node_assert_1.default.rejects(async () => {
53
+ await index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'flexapp'));
54
+ });
55
+ });
56
+ (0, node_test_1.it)('[sync] Positive: Must be created a symbolic link', () => {
57
+ index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'linkapp'), {
58
+ sync: true
59
+ });
60
+ const stat = node_fs_1.default.lstatSync(node_path_1.default.join(tmpDir, 'linkapp'));
61
+ (0, node_assert_1.default)(stat.isSymbolicLink());
62
+ });
63
+ (0, node_test_1.it)('[sync] Positive: Must be created a symbolic link for directory', () => {
64
+ index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'digest'), node_path_1.default.join(tmpDir, 'linkapp'), {
65
+ sync: true
66
+ });
67
+ const stat = node_fs_1.default.lstatSync(node_path_1.default.join(tmpDir, 'linkapp'));
68
+ (0, node_assert_1.default)(stat.isSymbolicLink());
69
+ });
70
+ (0, node_test_1.it)('[sync] Negative: Throw if destination already exists', () => {
71
+ node_assert_1.default.throws(() => {
72
+ index_1.pfs.symlink(node_path_1.default.join(tmpDir, 'tings.txt'), node_path_1.default.join(tmpDir, 'flexapp'), {
73
+ sync: true
74
+ });
75
+ });
76
+ });
77
+ });
@@ -0,0 +1,8 @@
1
+ import type { Mode, PoweredFileSystem } from '../powered-file-system';
2
+ /**
3
+ * Thin wrapper around `fs.access` that resolves paths against the instance root.
4
+ */
5
+ export declare function test<T extends boolean = false>(this: PoweredFileSystem, src: string, options?: {
6
+ sync?: T;
7
+ flag?: Mode;
8
+ }): T extends true ? boolean : Promise<boolean>;
@@ -0,0 +1,30 @@
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.test = test;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ /**
10
+ * Thin wrapper around `fs.access` that resolves paths against the instance root.
11
+ */
12
+ function test(src, options) {
13
+ const { sync = false, flag = 'e' } = options ?? {};
14
+ const mode = this.constants[flag];
15
+ src = node_path_1.default.resolve(this.pwd, src);
16
+ if (sync) {
17
+ try {
18
+ node_fs_1.default.accessSync(src, mode);
19
+ return true;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ return new Promise((resolve) => {
26
+ node_fs_1.default.access(src, mode, (err) => {
27
+ resolve(!err);
28
+ });
29
+ });
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
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 existence and access checks exposed by `test()`.
15
+ */
16
+ (0, node_test_1.describe)('test(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
+ (0, test_utils_1.fmock)({
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
+ });
28
+ });
29
+ (0, node_test_1.afterEach)(() => {
30
+ (0, test_utils_1.restore)(tmpDir);
31
+ });
32
+ (0, node_test_1.it)(`Positive: Should return 'true' for current working directory`, async () => {
33
+ const exist = await index_1.pfs.test('.');
34
+ (0, node_assert_1.default)(exist);
35
+ });
36
+ (0, node_test_1.it)(`Positive: For existing file should return 'true'`, async () => {
37
+ const exist = await index_1.pfs.test(node_path_1.default.join(tmpDir, 'tings.txt'));
38
+ (0, node_assert_1.default)(exist);
39
+ });
40
+ (0, node_test_1.it)(`Positive: For existing directory should return 'true'`, async () => {
41
+ const exist = await index_1.pfs.test(node_path_1.default.join(tmpDir, 'digest'));
42
+ (0, node_assert_1.default)(exist);
43
+ });
44
+ (0, node_test_1.it)(`Positive: A non-existent file must return 'false'`, async () => {
45
+ const guid = chance.guid();
46
+ const exist = await index_1.pfs.test(node_path_1.default.join(tmpDir, guid));
47
+ (0, node_assert_1.default)(exist === false);
48
+ });
49
+ (0, node_test_1.it)(`Positive: For existing file should return 'true'`, () => {
50
+ const exist = index_1.pfs.test(node_path_1.default.join(tmpDir, 'tings.txt'), {
51
+ sync: true
52
+ });
53
+ (0, node_assert_1.default)(exist);
54
+ });
55
+ (0, node_test_1.it)(`[sync] Positive: For existing directory should return 'true'`, () => {
56
+ const exist = index_1.pfs.test(node_path_1.default.join(tmpDir, 'digest'), {
57
+ sync: true
58
+ });
59
+ (0, node_assert_1.default)(exist);
60
+ });
61
+ (0, node_test_1.it)(`[sync] Positive: A non-existent file must return 'false'`, () => {
62
+ const guid = chance.guid();
63
+ const exist = index_1.pfs.test(node_path_1.default.join(tmpDir, guid), {
64
+ sync: true
65
+ });
66
+ (0, node_assert_1.default)(exist === false);
67
+ });
68
+ (0, node_test_1.it)('[sync] Positive: Should respect access flag checks', () => {
69
+ node_fs_1.default.chmodSync(node_path_1.default.join(tmpDir, 'tings.txt'), 0o444);
70
+ const writable = index_1.pfs.test(node_path_1.default.join(tmpDir, 'tings.txt'), {
71
+ sync: true,
72
+ flag: 'w'
73
+ });
74
+ (0, node_assert_1.default)(writable === false);
75
+ });
76
+ });
@@ -0,0 +1,10 @@
1
+ import type { Flag, PoweredFileSystem } from '../powered-file-system';
2
+ /**
3
+ * Writes a file relative to `pwd` and then reapplies the computed permissions explicitly.
4
+ */
5
+ export declare function write<T extends boolean = false>(this: PoweredFileSystem, src: string, data: Buffer | string, options?: {
6
+ sync?: T;
7
+ encoding?: BufferEncoding | null;
8
+ umask?: number;
9
+ flag?: Flag;
10
+ }): T extends true ? void : Promise<void>;
@@ -0,0 +1,36 @@
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.write = write;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ /**
10
+ * Writes a file relative to `pwd` and then reapplies the computed permissions explicitly.
11
+ */
12
+ function write(src, data, options) {
13
+ const { sync = false, encoding = 'utf8', umask = 0o000, flag = 'w', } = options ?? {};
14
+ src = node_path_1.default.resolve(this.pwd, src);
15
+ const mode = 0o666 & ~umask;
16
+ if (sync) {
17
+ // Apply chmod explicitly so the final mode is deterministic across runtimes.
18
+ node_fs_1.default.writeFileSync(src, data, { encoding, mode, flag });
19
+ node_fs_1.default.chmodSync(src, mode);
20
+ return undefined;
21
+ }
22
+ return new Promise((resolve, reject) => {
23
+ node_fs_1.default.writeFile(src, data, { encoding, mode, flag }, (err) => {
24
+ if (err) {
25
+ return reject(err);
26
+ }
27
+ // Align async behavior with the synchronous branch.
28
+ node_fs_1.default.chmod(src, mode, (err) => {
29
+ if (err) {
30
+ return reject(err);
31
+ }
32
+ resolve();
33
+ });
34
+ });
35
+ });
36
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,97 @@
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
+ * Covers file writes, overwrite behavior, and explicit mode handling.
15
+ */
16
+ const itUnix = process.platform === 'win32' ? node_test_1.it.skip : node_test_1.it;
17
+ (0, node_test_1.describe)('write(src, data[, options])', () => {
18
+ const chance = new chance_1.default();
19
+ let tmpDir = '';
20
+ (0, node_test_1.beforeEach)(() => {
21
+ tmpDir = (0, test_utils_1.createTmpDir)();
22
+ (0, test_utils_1.fmock)({
23
+ [node_path_1.default.join(tmpDir, 'tings.txt')]: {
24
+ type: 'file',
25
+ data: chance.string()
26
+ }
27
+ });
28
+ });
29
+ (0, node_test_1.afterEach)(() => {
30
+ (0, test_utils_1.restore)(tmpDir);
31
+ });
32
+ (0, node_test_1.it)('Positive: Must write content to file', async () => {
33
+ const payload = chance.paragraph();
34
+ const guid = chance.guid();
35
+ const filePath = node_path_1.default.join(tmpDir, `${guid}.txt`);
36
+ await index_1.pfs.write(filePath, payload);
37
+ const { size } = node_fs_1.default.lstatSync(filePath);
38
+ (0, node_assert_1.default)(payload.length === size);
39
+ });
40
+ (0, node_test_1.it)('Positive: Must rewrite content if file already exists', async () => {
41
+ const payload = chance.paragraph();
42
+ await index_1.pfs.write(node_path_1.default.join(tmpDir, 'tings.txt'), payload);
43
+ const { size } = node_fs_1.default.lstatSync(node_path_1.default.join(tmpDir, 'tings.txt'));
44
+ (0, node_assert_1.default)(payload.length === size);
45
+ });
46
+ (0, node_test_1.it)('Negative: Throw if resource is directory', async () => {
47
+ const payload = chance.paragraph();
48
+ await node_assert_1.default.rejects(async () => {
49
+ await index_1.pfs.write(tmpDir, payload);
50
+ });
51
+ });
52
+ (0, node_test_1.it)(`Negative: Unexpected option 'flag' returns Error`, async () => {
53
+ const payload = chance.paragraph();
54
+ await node_assert_1.default.rejects(async () => {
55
+ await index_1.pfs.write(node_path_1.default.join(tmpDir, 'tings.txt'), payload, {
56
+ flag: 'r'
57
+ });
58
+ });
59
+ });
60
+ (0, node_test_1.it)('[sync] Positive: Write contents even to a non-existent file', () => {
61
+ const payload = chance.paragraph();
62
+ const guid = chance.guid();
63
+ const filePath = node_path_1.default.join(tmpDir, `${guid}.txt`);
64
+ index_1.pfs.write(filePath, payload, {
65
+ sync: true
66
+ });
67
+ const content = node_fs_1.default.readFileSync(filePath, 'utf8');
68
+ (0, node_assert_1.default)(payload === content);
69
+ });
70
+ (0, node_test_1.it)('[sync] Negative: Throw if resource is directory', () => {
71
+ const payload = chance.paragraph();
72
+ node_assert_1.default.throws(() => {
73
+ index_1.pfs.write(tmpDir, payload, {
74
+ sync: true
75
+ });
76
+ });
77
+ });
78
+ (0, node_test_1.it)(`[sync] Negative: Unexpected option 'flag' returns Error`, () => {
79
+ const payload = chance.paragraph();
80
+ node_assert_1.default.throws(() => {
81
+ index_1.pfs.write(node_path_1.default.join(tmpDir, 'tings.txt'), payload, {
82
+ sync: true,
83
+ flag: 'r'
84
+ });
85
+ });
86
+ });
87
+ itUnix('[sync] Positive: Umask should be applied with bit masking', () => {
88
+ const guid = chance.guid();
89
+ const filePath = node_path_1.default.join(tmpDir, `${guid}.txt`);
90
+ index_1.pfs.write(filePath, 'x', {
91
+ sync: true,
92
+ umask: 0o111
93
+ });
94
+ const mode = node_fs_1.default.statSync(filePath).mode & 0o777;
95
+ (0, node_assert_1.default)(mode === 0o666);
96
+ });
97
+ });
@@ -1,7 +1,10 @@
1
1
  import fs from 'node:fs';
2
2
  import { bitmask } from './bitmask';
3
+ /**
4
+ * Public API entrypoint for the path-aware file system wrapper.
5
+ */
3
6
  export type Mode = keyof IConstants;
4
- export type Flag = Mode | 'a';
7
+ export type Flag = Extract<fs.OpenMode, string>;
5
8
  export type Stats = fs.Stats;
6
9
  export * from './bitmask';
7
10
  export interface IConstants {
@@ -10,45 +13,89 @@ export interface IConstants {
10
13
  w: number;
11
14
  x: number;
12
15
  }
16
+ /**
17
+ * Path-aware wrapper around Node's file system APIs.
18
+ *
19
+ * All relative paths are resolved against `pwd`, which makes the instance
20
+ * suitable for sandboxed or virtual working-directory workflows.
21
+ */
13
22
  export declare class PoweredFileSystem {
14
23
  readonly pwd: string;
24
+ /**
25
+ * Access mode aliases used by `test()`.
26
+ */
15
27
  readonly constants: IConstants;
28
+ /**
29
+ * Exposes permission mask normalization as a static helper.
30
+ */
16
31
  static bitmask: typeof bitmask;
32
+ /**
33
+ * @param pwd Base directory used to resolve all relative paths.
34
+ */
17
35
  constructor(pwd?: string);
18
- private resolve;
36
+ /**
37
+ * Checks whether the given path is accessible with the requested mode.
38
+ */
19
39
  test<T extends boolean = false>(src: string, options?: {
20
40
  sync?: T;
21
41
  flag?: Mode;
22
42
  }): T extends true ? boolean : Promise<boolean>;
43
+ /**
44
+ * Returns `lstat` information for a path.
45
+ */
23
46
  stat<T extends boolean = false>(src: string, options?: {
24
47
  sync?: T;
25
48
  }): T extends true ? Stats : Promise<Stats>;
49
+ /**
50
+ * Applies a mode recursively to a file or directory tree.
51
+ */
26
52
  chmod<T extends boolean = false>(src: string, mode: number, options?: {
27
53
  sync?: T;
28
54
  }): T extends true ? void : Promise<void>;
55
+ /**
56
+ * Applies ownership recursively to a file or directory tree.
57
+ */
29
58
  chown<T extends boolean = false>(src: string, options?: {
30
59
  sync?: T;
31
60
  uid?: number;
32
61
  gid?: number;
33
62
  }): T extends true ? void : Promise<void>;
63
+ /**
64
+ * Creates a symbolic link from `dest` to `src`.
65
+ */
34
66
  symlink<T extends boolean = false>(src: string, dest: string, options?: {
35
67
  sync?: T;
36
68
  }): T extends true ? void : Promise<void>;
69
+ /**
70
+ * Copies `src` into the destination directory.
71
+ */
37
72
  copy<T extends boolean = false>(src: string, dest: string, options?: {
38
73
  sync?: T;
39
74
  umask?: number;
40
75
  }): T extends true ? void : Promise<void>;
76
+ /**
77
+ * Renames or moves a file system node.
78
+ */
41
79
  rename<T extends boolean = false>(src: string, dest: string, options?: {
42
80
  sync?: T;
43
81
  }): T extends true ? void : Promise<void>;
82
+ /**
83
+ * Removes a file system node recursively.
84
+ */
44
85
  remove<T extends boolean = false>(src: string, options?: {
45
86
  sync?: T;
46
87
  }): T extends true ? void : Promise<void>;
88
+ /**
89
+ * Reads a file relative to the current instance root.
90
+ */
47
91
  read<T extends boolean = false>(src: string, options?: {
48
92
  sync?: T;
49
93
  encoding?: BufferEncoding | null;
50
94
  flag?: Flag;
51
95
  }): T extends true ? string | Buffer : Promise<string | Buffer>;
96
+ /**
97
+ * Writes a file and applies the resulting permissions explicitly.
98
+ */
52
99
  write<T extends boolean = false>(src: string, data: Buffer | string, options?: {
53
100
  sync?: T;
54
101
  encoding?: BufferEncoding | null;
@@ -56,17 +103,23 @@ export declare class PoweredFileSystem {
56
103
  flag?: Flag;
57
104
  }): T extends true ? void : Promise<void>;
58
105
  /**
59
- * @deprecated The method should not be used
60
- */
106
+ * @deprecated Use `write(..., { flag: 'a' })` instead.
107
+ */
61
108
  append<T extends boolean = false>(src: string, data: Buffer | string, options?: {
62
109
  sync?: T;
63
110
  encoding?: BufferEncoding | null;
64
111
  umask?: number;
65
112
  }): T extends true ? void : Promise<void>;
113
+ /**
114
+ * Lists directory entries relative to the current instance root.
115
+ */
66
116
  readdir<T extends boolean = false>(dir: string, options?: {
67
117
  sync?: T;
68
118
  encoding?: BufferEncoding | null;
69
119
  }): T extends true ? string[] : Promise<string[]>;
120
+ /**
121
+ * Creates a directory tree relative to the current instance root.
122
+ */
70
123
  mkdir<T extends boolean = false>(dir: string, options?: {
71
124
  sync?: T;
72
125
  umask?: number;