@zenfs/core 1.2.7 → 1.2.9
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/backends/backend.d.ts +2 -1
- package/dist/backends/fetch.d.ts +10 -3
- package/dist/backends/fetch.js +9 -15
- package/dist/backends/memory.d.ts +0 -1
- package/dist/backends/memory.js +1 -5
- package/dist/backends/port/fs.d.ts +0 -2
- package/dist/backends/port/fs.js +0 -2
- package/dist/backends/store/fs.js +10 -10
- package/dist/config.js +32 -9
- package/dist/credentials.d.ts +3 -0
- package/dist/credentials.js +3 -0
- package/dist/devices.d.ts +50 -13
- package/dist/devices.js +32 -6
- package/dist/emulation/promises.js +3 -13
- package/dist/emulation/shared.d.ts +4 -1
- package/dist/emulation/shared.js +5 -3
- package/dist/emulation/sync.js +3 -14
- package/dist/mixins/async.js +2 -2
- package/package.json +2 -1
- package/readme.md +4 -0
- package/src/backends/backend.ts +2 -1
- package/src/backends/fetch.ts +18 -18
- package/src/backends/memory.ts +1 -5
- package/src/backends/port/fs.ts +0 -2
- package/src/backends/store/fs.ts +18 -18
- package/src/config.ts +33 -10
- package/src/credentials.ts +3 -0
- package/src/devices.ts +75 -12
- package/src/emulation/promises.ts +3 -14
- package/src/emulation/shared.ts +5 -3
- package/src/emulation/sync.ts +3 -15
- package/src/mixins/async.ts +2 -2
- package/tests/fs/directory.test.ts +83 -1
- package/tests/fs/permissions.test.ts +45 -2
- package/tests/mounts.test.ts +18 -0
- package/tests/fs/chmod.test.ts +0 -44
- package/tests/fs/readdir.test.ts +0 -87
|
@@ -3,7 +3,22 @@ import { suite, test } from 'node:test';
|
|
|
3
3
|
import { ErrnoError } from '../../dist/error.js';
|
|
4
4
|
import { fs } from '../common.js';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const testDir = 'test-dir';
|
|
7
|
+
const testFiles = ['file1.txt', 'file2.txt', 'file3.txt'];
|
|
8
|
+
const testDirectories = ['subdir1', 'subdir2'];
|
|
9
|
+
|
|
10
|
+
await fs.promises.mkdir(testDir);
|
|
11
|
+
for (const file of testFiles) {
|
|
12
|
+
await fs.promises.writeFile(`${testDir}/${file}`, 'Sample content');
|
|
13
|
+
}
|
|
14
|
+
for (const dir of testDirectories) {
|
|
15
|
+
await fs.promises.mkdir(`${testDir}/${dir}`);
|
|
16
|
+
for (const file of ['file4.txt', 'file5.txt']) {
|
|
17
|
+
await fs.promises.writeFile(`${testDir}/${dir}/${file}`, 'Sample content');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
suite('Directories', () => {
|
|
7
22
|
test('mkdir', async () => {
|
|
8
23
|
await fs.promises.mkdir('/one', 0o755);
|
|
9
24
|
assert(await fs.promises.exists('/one'));
|
|
@@ -126,4 +141,71 @@ suite('Directory', () => {
|
|
|
126
141
|
|
|
127
142
|
fs.rmSync('/rmDirRecusrively', { recursive: true });
|
|
128
143
|
});
|
|
144
|
+
|
|
145
|
+
test('readdir returns files and directories', async () => {
|
|
146
|
+
const dirents = await fs.promises.readdir(testDir, { withFileTypes: true });
|
|
147
|
+
const files = dirents.filter(dirent => dirent.isFile()).map(dirent => dirent.name);
|
|
148
|
+
const dirs = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
|
|
149
|
+
|
|
150
|
+
assert(testFiles.every(file => files.includes(file)));
|
|
151
|
+
assert(testDirectories.every(dir => dirs.includes(dir)));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('readdirSync returns files and directories', () => {
|
|
155
|
+
const dirents = fs.readdirSync(testDir, { withFileTypes: true });
|
|
156
|
+
const files = dirents.filter(dirent => dirent.isFile()).map(dirent => dirent.name);
|
|
157
|
+
const dirs = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
|
|
158
|
+
|
|
159
|
+
assert(testFiles.every(file => files.includes(file)));
|
|
160
|
+
assert(testDirectories.every(dir => dirs.includes(dir)));
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('readdir returns Dirent objects', async () => {
|
|
164
|
+
const dirents = await fs.promises.readdir(testDir, { withFileTypes: true });
|
|
165
|
+
assert(dirents[0] instanceof fs.Dirent);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('readdirSync returns Dirent objects', () => {
|
|
169
|
+
const dirents = fs.readdirSync(testDir, { withFileTypes: true });
|
|
170
|
+
assert(dirents[0] instanceof fs.Dirent);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('readdir works without withFileTypes option', async () => {
|
|
174
|
+
const files = await fs.promises.readdir(testDir);
|
|
175
|
+
assert(testFiles.every(entry => files.includes(entry)));
|
|
176
|
+
assert(testDirectories.every(entry => files.includes(entry)));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test('readdirSync works without withFileTypes option', () => {
|
|
180
|
+
const files = fs.readdirSync(testDir);
|
|
181
|
+
assert(testFiles.every(entry => files.includes(entry)));
|
|
182
|
+
assert(testDirectories.every(entry => files.includes(entry)));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('readdir returns files recursively', async () => {
|
|
186
|
+
const entries = await fs.promises.readdir(testDir, { recursive: true });
|
|
187
|
+
assert(entries.includes('file1.txt'));
|
|
188
|
+
assert(entries.includes('subdir1/file4.txt'));
|
|
189
|
+
assert(entries.includes('subdir2/file5.txt'));
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('readdir returns Dirent recursively', async () => {
|
|
193
|
+
const entries = await fs.promises.readdir(testDir, { recursive: true, withFileTypes: true });
|
|
194
|
+
assert(entries.find(entry => entry.path === 'file1.txt'));
|
|
195
|
+
assert(entries.find(entry => entry.path === 'subdir1/file4.txt'));
|
|
196
|
+
assert(entries.find(entry => entry.path === 'subdir2/file5.txt'));
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// New test for readdirSync with recursive: true
|
|
200
|
+
test('readdirSync returns files recursively', () => {
|
|
201
|
+
const entries = fs.readdirSync(testDir, { recursive: true });
|
|
202
|
+
assert(entries.includes('file1.txt'));
|
|
203
|
+
assert(entries.includes('subdir1/file4.txt'));
|
|
204
|
+
assert(entries.includes('subdir2/file5.txt'));
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('Cyrillic file names', () => {
|
|
208
|
+
fs.writeFileSync('/мой-файл.txt', 'HELLO!', 'utf-8');
|
|
209
|
+
assert(fs.readdirSync('/').includes('мой-файл.txt'));
|
|
210
|
+
});
|
|
129
211
|
});
|
|
@@ -1,12 +1,52 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
+
import { credentials } from '../../dist/credentials.js';
|
|
3
4
|
import { R_OK, W_OK, X_OK } from '../../dist/emulation/constants.js';
|
|
4
5
|
import { join } from '../../dist/emulation/path.js';
|
|
5
6
|
import { ErrnoError } from '../../dist/error.js';
|
|
6
7
|
import { encodeUTF8 } from '../../dist/utils.js';
|
|
7
8
|
import { fs } from '../common.js';
|
|
8
9
|
|
|
10
|
+
const asyncMode = 0o777;
|
|
11
|
+
const syncMode = 0o644;
|
|
12
|
+
const file = 'a.js';
|
|
13
|
+
|
|
9
14
|
suite('Permissions', () => {
|
|
15
|
+
test('chmod', async () => {
|
|
16
|
+
await fs.promises.chmod(file, asyncMode.toString(8));
|
|
17
|
+
|
|
18
|
+
const stats = await fs.promises.stat(file);
|
|
19
|
+
assert.equal(stats.mode & 0o777, asyncMode);
|
|
20
|
+
|
|
21
|
+
fs.chmodSync(file, syncMode);
|
|
22
|
+
assert.equal(fs.statSync(file).mode & 0o777, syncMode);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('fchmod', async () => {
|
|
26
|
+
const handle = await fs.promises.open(file, 'a', 0o644);
|
|
27
|
+
|
|
28
|
+
await handle.chmod(asyncMode);
|
|
29
|
+
const stats = await handle.stat();
|
|
30
|
+
|
|
31
|
+
assert.equal(stats.mode & 0o777, asyncMode);
|
|
32
|
+
|
|
33
|
+
fs.fchmodSync(handle.fd, syncMode);
|
|
34
|
+
assert.equal(fs.statSync(file).mode & 0o777, syncMode);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('lchmod', async () => {
|
|
38
|
+
const link = 'symbolic-link';
|
|
39
|
+
|
|
40
|
+
await fs.promises.symlink(file, link);
|
|
41
|
+
await fs.promises.lchmod(link, asyncMode);
|
|
42
|
+
|
|
43
|
+
const stats = await fs.promises.lstat(link);
|
|
44
|
+
assert.equal(stats.mode & 0o777, asyncMode);
|
|
45
|
+
|
|
46
|
+
fs.lchmodSync(link, syncMode);
|
|
47
|
+
assert.equal(fs.lstatSync(link).mode & 0o777, syncMode);
|
|
48
|
+
});
|
|
49
|
+
|
|
10
50
|
async function test_item(path: string): Promise<void> {
|
|
11
51
|
const stats = await fs.promises.stat(path).catch((error: ErrnoError) => {
|
|
12
52
|
assert(error instanceof ErrnoError);
|
|
@@ -27,7 +67,7 @@ suite('Permissions', () => {
|
|
|
27
67
|
|
|
28
68
|
if (stats.isDirectory()) {
|
|
29
69
|
for (const dir of await fs.promises.readdir(path)) {
|
|
30
|
-
await test_item(join(path, dir));
|
|
70
|
+
await test('Access controls: ' + join(path, dir), () => test_item(join(path, dir)));
|
|
31
71
|
}
|
|
32
72
|
} else {
|
|
33
73
|
await fs.promises.readFile(path).catch(checkError(R_OK));
|
|
@@ -48,5 +88,8 @@ suite('Permissions', () => {
|
|
|
48
88
|
assert(stats.hasAccess(R_OK));
|
|
49
89
|
}
|
|
50
90
|
|
|
51
|
-
|
|
91
|
+
const copy = { ...credentials };
|
|
92
|
+
Object.assign(credentials, { uid: 1000, gid: 1000, euid: 1000, egid: 1000 });
|
|
93
|
+
test('Access controls: /', () => test_item('/'));
|
|
94
|
+
Object.assign(credentials, copy);
|
|
52
95
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { suite, test } from 'node:test';
|
|
3
|
+
import { configure } from '../src/config.js';
|
|
4
|
+
import * as fs from '../src/emulation/index.js';
|
|
5
|
+
import { InMemory } from '../src/index.js';
|
|
6
|
+
|
|
7
|
+
suite('Mounts', () => {
|
|
8
|
+
test('Mount in nested directory', async () => {
|
|
9
|
+
await configure({
|
|
10
|
+
mounts: {
|
|
11
|
+
'/nested/dir': InMemory,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
assert.deepStrictEqual(fs.readdirSync('/'), ['nested']);
|
|
16
|
+
assert.deepStrictEqual(fs.readdirSync('/nested'), ['dir']);
|
|
17
|
+
});
|
|
18
|
+
});
|
package/tests/fs/chmod.test.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
3
|
-
import { fs } from '../common.js';
|
|
4
|
-
|
|
5
|
-
const asyncMode = 0o777;
|
|
6
|
-
const syncMode = 0o644;
|
|
7
|
-
const file = 'a.js';
|
|
8
|
-
|
|
9
|
-
suite('chmod tests', () => {
|
|
10
|
-
test('chmod', async () => {
|
|
11
|
-
await fs.promises.chmod(file, asyncMode.toString(8));
|
|
12
|
-
|
|
13
|
-
const stats = await fs.promises.stat(file);
|
|
14
|
-
assert.equal(stats.mode & 0o777, asyncMode);
|
|
15
|
-
|
|
16
|
-
fs.chmodSync(file, syncMode);
|
|
17
|
-
assert.equal(fs.statSync(file).mode & 0o777, syncMode);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('fchmod', async () => {
|
|
21
|
-
const handle = await fs.promises.open(file, 'a', 0o644);
|
|
22
|
-
|
|
23
|
-
await handle.chmod(asyncMode);
|
|
24
|
-
const stats = await handle.stat();
|
|
25
|
-
|
|
26
|
-
assert.equal(stats.mode & 0o777, asyncMode);
|
|
27
|
-
|
|
28
|
-
fs.fchmodSync(handle.fd, syncMode);
|
|
29
|
-
assert.equal(fs.statSync(file).mode & 0o777, syncMode);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('lchmod', async () => {
|
|
33
|
-
const link = 'symbolic-link';
|
|
34
|
-
|
|
35
|
-
await fs.promises.symlink(file, link);
|
|
36
|
-
await fs.promises.lchmod(link, asyncMode);
|
|
37
|
-
|
|
38
|
-
const stats = await fs.promises.lstat(link);
|
|
39
|
-
assert.equal(stats.mode & 0o777, asyncMode);
|
|
40
|
-
|
|
41
|
-
fs.lchmodSync(link, syncMode);
|
|
42
|
-
assert.equal(fs.lstatSync(link).mode & 0o777, syncMode);
|
|
43
|
-
});
|
|
44
|
-
});
|
package/tests/fs/readdir.test.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
3
|
-
import { fs } from '../common.js';
|
|
4
|
-
|
|
5
|
-
const testDir = 'test-dir';
|
|
6
|
-
const testFiles = ['file1.txt', 'file2.txt', 'file3.txt'];
|
|
7
|
-
const testDirectories = ['subdir1', 'subdir2'];
|
|
8
|
-
|
|
9
|
-
await fs.promises.mkdir(testDir);
|
|
10
|
-
for (const file of testFiles) {
|
|
11
|
-
await fs.promises.writeFile(`${testDir}/${file}`, 'Sample content');
|
|
12
|
-
}
|
|
13
|
-
for (const dir of testDirectories) {
|
|
14
|
-
await fs.promises.mkdir(`${testDir}/${dir}`);
|
|
15
|
-
for (const file of ['file4.txt', 'file5.txt']) {
|
|
16
|
-
await fs.promises.writeFile(`${testDir}/${dir}/${file}`, 'Sample content');
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
suite('readdir and readdirSync', () => {
|
|
21
|
-
test('readdir returns files and directories', async () => {
|
|
22
|
-
const dirents = await fs.promises.readdir(testDir, { withFileTypes: true });
|
|
23
|
-
const files = dirents.filter(dirent => dirent.isFile()).map(dirent => dirent.name);
|
|
24
|
-
const dirs = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
|
|
25
|
-
|
|
26
|
-
assert(testFiles.every(file => files.includes(file)));
|
|
27
|
-
assert(testDirectories.every(dir => dirs.includes(dir)));
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('readdirSync returns files and directories', () => {
|
|
31
|
-
const dirents = fs.readdirSync(testDir, { withFileTypes: true });
|
|
32
|
-
const files = dirents.filter(dirent => dirent.isFile()).map(dirent => dirent.name);
|
|
33
|
-
const dirs = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
|
|
34
|
-
|
|
35
|
-
assert(testFiles.every(file => files.includes(file)));
|
|
36
|
-
assert(testDirectories.every(dir => dirs.includes(dir)));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('readdir returns Dirent objects', async () => {
|
|
40
|
-
const dirents = await fs.promises.readdir(testDir, { withFileTypes: true });
|
|
41
|
-
assert(dirents[0] instanceof fs.Dirent);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('readdirSync returns Dirent objects', () => {
|
|
45
|
-
const dirents = fs.readdirSync(testDir, { withFileTypes: true });
|
|
46
|
-
assert(dirents[0] instanceof fs.Dirent);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('readdir works without withFileTypes option', async () => {
|
|
50
|
-
const files = await fs.promises.readdir(testDir);
|
|
51
|
-
assert(testFiles.every(entry => files.includes(entry)));
|
|
52
|
-
assert(testDirectories.every(entry => files.includes(entry)));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('readdirSync works without withFileTypes option', () => {
|
|
56
|
-
const files = fs.readdirSync(testDir);
|
|
57
|
-
assert(testFiles.every(entry => files.includes(entry)));
|
|
58
|
-
assert(testDirectories.every(entry => files.includes(entry)));
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('readdir returns files recursively', async () => {
|
|
62
|
-
const entries = await fs.promises.readdir(testDir, { recursive: true });
|
|
63
|
-
assert(entries.includes('file1.txt'));
|
|
64
|
-
assert(entries.includes('subdir1/file4.txt'));
|
|
65
|
-
assert(entries.includes('subdir2/file5.txt'));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('readdir returns Dirent recursively', async () => {
|
|
69
|
-
const entries = await fs.promises.readdir(testDir, { recursive: true, withFileTypes: true });
|
|
70
|
-
assert(entries.find(entry => entry.path === 'file1.txt'));
|
|
71
|
-
assert(entries.find(entry => entry.path === 'subdir1/file4.txt'));
|
|
72
|
-
assert(entries.find(entry => entry.path === 'subdir2/file5.txt'));
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// New test for readdirSync with recursive: true
|
|
76
|
-
test('readdirSync returns files recursively', () => {
|
|
77
|
-
const entries = fs.readdirSync(testDir, { recursive: true });
|
|
78
|
-
assert(entries.includes('file1.txt'));
|
|
79
|
-
assert(entries.includes('subdir1/file4.txt'));
|
|
80
|
-
assert(entries.includes('subdir2/file5.txt'));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('Cyrillic file names', () => {
|
|
84
|
-
fs.writeFileSync('/мой-файл.txt', 'HELLO!', 'utf-8');
|
|
85
|
-
assert(fs.readdirSync('/').includes('мой-файл.txt'));
|
|
86
|
-
});
|
|
87
|
-
});
|