@zenfs/core 2.6.2 → 2.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +1 -1
  2. package/dist/backends/single_buffer.js +34 -11
  3. package/dist/context.js +1 -0
  4. package/dist/internal/contexts.d.ts +3 -1
  5. package/dist/internal/contexts.js +11 -1
  6. package/dist/internal/inode.d.ts +2 -0
  7. package/dist/internal/inode.js +2 -0
  8. package/dist/internal/rpc.d.ts +4 -4
  9. package/dist/node/async.d.ts +11 -1
  10. package/dist/node/async.js +14 -35
  11. package/dist/node/index.d.ts +1 -0
  12. package/dist/node/index.js +1 -0
  13. package/dist/node/promises.d.ts +17 -3
  14. package/dist/node/promises.js +32 -16
  15. package/dist/node/stats.d.ts +12 -0
  16. package/dist/node/stats.js +35 -6
  17. package/dist/node/sync.d.ts +39 -11
  18. package/dist/node/sync.js +41 -17
  19. package/dist/node/utf8stream.d.ts +99 -0
  20. package/dist/node/utf8stream.js +690 -0
  21. package/dist/utils.d.ts +10 -0
  22. package/dist/utils.js +17 -0
  23. package/dist/vfs/shared.js +9 -7
  24. package/package.json +14 -10
  25. package/scripts/test.js +15 -8
  26. package/tests/backend/single-buffer-rotate.worker.js +19 -0
  27. package/tests/backend/single-buffer.test.ts +106 -0
  28. package/tests/common/context.test.ts +38 -0
  29. package/tests/common/glob.test.ts +86 -1
  30. package/tests/common/utf8stream.test.ts +164 -0
  31. package/tests/common.ts +4 -2
  32. package/tests/fetch/fetch.ts +1 -1
  33. package/tests/fetch/run.sh +1 -1
  34. package/tests/fs/append.test.ts +1 -1
  35. package/tests/fs/concurrency.test.ts +1 -1
  36. package/tests/fs/dir.test.ts +1 -1
  37. package/tests/fs/directory.test.ts +3 -3
  38. package/tests/fs/errors.test.ts +1 -1
  39. package/tests/fs/exists.test.ts +3 -3
  40. package/tests/fs/links.test.ts +5 -5
  41. package/tests/fs/open.test.ts +5 -5
  42. package/tests/fs/permissions.test.ts +5 -5
  43. package/tests/fs/read.test.ts +3 -3
  44. package/tests/fs/readFile.test.ts +2 -2
  45. package/tests/fs/rename.test.ts +5 -5
  46. package/tests/fs/scaling.test.ts +1 -1
  47. package/tests/fs/stat.test.ts +32 -3
  48. package/tests/fs/streams.test.ts +1 -1
  49. package/tests/fs/tempdir.test.ts +1 -1
  50. package/tests/fs/times.test.ts +2 -2
  51. package/tests/fs/truncate.test.ts +1 -1
  52. package/tests/fs/watch.test.ts +1 -1
  53. package/tests/fs/write.test.ts +2 -2
  54. package/tests/fs/xattr.test.ts +1 -1
  55. package/tests/{native/setup.ts → native-setup.ts} +5 -5
  56. package/tests/setup/context.ts +1 -1
  57. package/tests/setup/cow.ts +1 -1
  58. package/tests/setup/index.ts +1 -1
  59. package/tests/setup/memory.ts +1 -1
  60. package/tests/setup/port.ts +1 -1
  61. package/tests/setup/single-buffer.ts +1 -1
  62. package/tests/setup.ts +1 -1
  63. package/tests/tsconfig.json +2 -1
  64. package/tests/native/run.sh +0 -3
package/tests/common.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import { fs as defaultFS } from '@zenfs/core';
3
- import type { NodeFS } from '@zenfs/core/node/types.js';
3
+ import type { NodeFS } from '@zenfs/core/node/types';
4
4
  import { join, resolve } from 'node:path';
5
5
  import { styleText } from 'node:util';
6
6
  import { setupLogs } from './logs.js';
@@ -41,7 +41,9 @@ export type TestFlag =
41
41
  | 'xattr'
42
42
  | 'times'
43
43
  | 'tempdir'
44
- | 'lchmod';
44
+ | 'lchmod'
45
+ | 'promises.exists'
46
+ | 'root';
45
47
 
46
48
  /**
47
49
  * Whether a backend supports a flag.
@@ -1,6 +1,6 @@
1
1
  import { configure, Fetch } from '@zenfs/core';
2
2
  import { log } from 'kerium';
3
- import type { TestFlag, TestFlagState } from '../common.js';
3
+ import type { TestFlag, TestFlagState } from '../common.ts';
4
4
  import { baseUrl } from './config.js';
5
5
 
6
6
  await configure({
@@ -12,6 +12,6 @@ until nc -z localhost 26514; do
12
12
  sleep 0.25
13
13
  done
14
14
 
15
- npx --silent zenfs-test $SCRIPT_DIR/fetch.ts --preserve --force "$@"
15
+ npx --silent zenfs-test $SCRIPT_DIR/fetch.ts --preserve --force --node "$@"
16
16
 
17
17
  kill $PID
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { fs, config } from '../common.js';
4
+ import { fs, config } from '../common.ts';
5
5
 
6
6
  const content = 'Sample content',
7
7
  original = 'ABCD';
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  suite('Concurrency', config('write', 'async'), () => {
7
7
  test('parallel writeFile in the same directory does not lose entries #256', async () => {
@@ -2,7 +2,7 @@
2
2
  import { sync, type Dirent } from '@zenfs/core';
3
3
  import assert, { rejects } from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  const testFile = 'test-file.txt';
8
8
  fs.writeFileSync(testFile, 'Sample content');
@@ -2,7 +2,7 @@
2
2
  import assert from 'node:assert/strict';
3
3
  import { join } from 'node:path/posix';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  const testDir = 'test-dir';
8
8
  const testFiles = ['file1.txt', 'file2.txt', 'file3.txt'];
@@ -22,7 +22,7 @@ for (const dir of testDirectories) {
22
22
  suite('Directories', config('directories'), () => {
23
23
  test('mkdir', config('async'), async () => {
24
24
  await fs.promises.mkdir('/one', 0o755);
25
- assert(await fs.promises.exists('/one'));
25
+ assert(await fs.promises.stat('/one', { throwIfNoEntry: false }));
26
26
  await assert.rejects(fs.promises.mkdir('/one', 0o755), { code: 'EEXIST' });
27
27
  });
28
28
 
@@ -30,7 +30,7 @@ suite('Directories', config('directories'), () => {
30
30
 
31
31
  test('mkdir, nested', config('async'), async () => {
32
32
  await assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested/dir' });
33
- assert(!(await fs.promises.exists('/nested/dir')));
33
+ assert(!(await fs.promises.stat('/nested/dir', { throwIfNoEntry: false })));
34
34
  });
35
35
 
36
36
  test('mkdir, recursive', config('async'), async () => {
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import test, { suite } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  const existingFile = '/exit.js';
7
7
  const path = '/non-existent';
@@ -1,17 +1,17 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  suite('exists', () => {
7
7
  const f = 'x.txt';
8
8
 
9
- test('return true for an existing file', config('async'), async () => {
9
+ test('return true for an existing file', config('async', 'promises.exists'), async () => {
10
10
  const exists = await fs.promises.exists(f);
11
11
  assert(exists);
12
12
  });
13
13
 
14
- test('return false for a non-existent file', config('async'), async () => {
14
+ test('return false for a non-existent file', config('async', 'promises.exists'), async () => {
15
15
  const exists = await fs.promises.exists(f + '-NO');
16
16
  assert(!exists);
17
17
  });
@@ -2,7 +2,7 @@
2
2
  import { join } from '@zenfs/core/path';
3
3
  import assert from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  suite('Links', config('symlinks'), () => {
8
8
  const target = '/a1.js',
@@ -64,8 +64,8 @@ suite('Links', config('symlinks'), () => {
64
64
 
65
65
  test('unlink', async () => {
66
66
  await fs.promises.unlink(symlink);
67
- assert(!(await fs.promises.exists(symlink)));
68
- assert(await fs.promises.exists(target));
67
+ assert(!(await fs.promises.stat(symlink, { throwIfNoEntry: false })));
68
+ assert(await fs.promises.stat(target, { throwIfNoEntry: false }));
69
69
  });
70
70
 
71
71
  test('link', config('links'), async () => {
@@ -99,7 +99,7 @@ suite('Links', config('symlinks'), () => {
99
99
  // A link pointing at a directory satisfies a recursive mkdir and is left as a link
100
100
  assert.equal(await fs.promises.mkdir('/mkdir-link', { recursive: true }), undefined);
101
101
  assert((await fs.promises.lstat('/mkdir-link')).isSymbolicLink());
102
- assert(!(await fs.promises.exists('/mkdir-missing')));
102
+ assert(!(await fs.promises.stat('/mkdir-missing', { throwIfNoEntry: false })));
103
103
  });
104
104
 
105
105
  test('mkdir follows symlinks for intermediate components', config('async'), async () => {
@@ -113,7 +113,7 @@ suite('Links', config('symlinks'), () => {
113
113
 
114
114
  // Node reports the link itself here, unlike `mkdirSync` which reports the requested path with ENOENT
115
115
  await assert.rejects(fs.promises.mkdir('/mkdir-dangling/x', { recursive: true }), { code: 'ENOTDIR', path: '/mkdir-dangling' });
116
- assert(!(await fs.promises.exists('/mkdir-missing')));
116
+ assert(!(await fs.promises.stat('/mkdir-missing', { throwIfNoEntry: false })));
117
117
  });
118
118
 
119
119
  test('mkdirSync does not follow a symlink at the final component', config('sync'), () => {
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  suite('Opening files', () => {
7
7
  const filename = 'a.js';
@@ -12,12 +12,12 @@ suite('Opening files', () => {
12
12
  });
13
13
 
14
14
  test('open file with mode "r"', config('async'), async () => {
15
- const { fd } = await fs.promises.open(filename, 'r');
16
- assert(fd >= -Infinity);
15
+ await using handle = await fs.promises.open(filename, 'r');
16
+ assert(handle.fd >= -Infinity);
17
17
  });
18
18
 
19
19
  test('open file with mode "rs"', config('async'), async () => {
20
- const { fd } = await fs.promises.open(filename, 'rs');
21
- assert(fd >= -Infinity);
20
+ await using handle = await fs.promises.open(filename, 'rs');
21
+ assert(handle.fd >= -Infinity);
22
22
  });
23
23
  });
@@ -1,13 +1,13 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import { R_OK, W_OK, X_OK } from '@zenfs/core/constants';
3
- import { defaultContext } from '@zenfs/core/internal/contexts.js';
4
- import { hasAccess } from '@zenfs/core/internal/inode.js';
3
+ import { defaultContext } from '@zenfs/core/internal/contexts';
4
+ import { hasAccess } from '@zenfs/core/internal/inode';
5
5
  import { join } from '@zenfs/core/path';
6
6
  import type { Exception } from 'kerium';
7
7
  import assert from 'node:assert/strict';
8
8
  import { suite, test } from 'node:test';
9
9
  import { encodeUTF8 } from 'utilium';
10
- import { config, fs } from '../common.js';
10
+ import { config, fs } from '../common.ts';
11
11
 
12
12
  const asyncMode = 0o777;
13
13
  const syncMode = 0o644;
@@ -25,7 +25,7 @@ suite('Permissions', config('permissions'), () => {
25
25
  });
26
26
 
27
27
  test('fchmod', config('sync', 'async'), async () => {
28
- const handle = await fs.promises.open(file, 'a', 0o644);
28
+ await using handle = await fs.promises.open(file, 'a', 0o644);
29
29
 
30
30
  await handle.chmod(asyncMode);
31
31
  const stats = await handle.stat();
@@ -58,7 +58,7 @@ suite('Permissions', config('permissions'), () => {
58
58
 
59
59
  function checkError(access: number) {
60
60
  return function (error: Exception) {
61
- assert(error instanceof Error);
61
+ assert(Error.isError(error));
62
62
  assert(!hasAccess(defaultContext, stats!, access));
63
63
  };
64
64
  }
@@ -5,7 +5,7 @@ import assert from 'node:assert/strict';
5
5
  import type { OpenMode, PathLike } from 'node:fs';
6
6
  import { suite, test } from 'node:test';
7
7
  import { promisify } from 'node:util';
8
- import { config, fs } from '../common.js';
8
+ import { config, fs } from '../common.ts';
9
9
 
10
10
  const filepath = 'x.txt';
11
11
  const expected = 'xyz\n';
@@ -13,7 +13,7 @@ const ellipses = '…'.repeat(10_000);
13
13
 
14
14
  suite('read', () => {
15
15
  test('read file asynchronously', config('async'), async () => {
16
- const handle = await fs.promises.open(filepath, 'r');
16
+ await using handle = await fs.promises.open(filepath, 'r');
17
17
  const { bytesRead, buffer } = await handle.read(Buffer.alloc(expected.length), 0, expected.length, 0);
18
18
  assert.equal(bytesRead, expected.length);
19
19
  assert.equal(buffer.toString(), expected);
@@ -46,7 +46,7 @@ suite('read', () => {
46
46
  const bufferSync = Buffer.alloc(expected.length);
47
47
 
48
48
  test('read file from handle asynchronously', config('async'), async () => {
49
- const handle = await fs.promises.open(filepath, 'r');
49
+ await using handle = await fs.promises.open(filepath, 'r');
50
50
  const { bytesRead } = await handle.read(bufferAsync, 0, expected.length, 0);
51
51
 
52
52
  assert.equal(bytesRead, expected.length);
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  suite('Reading', () => {
7
7
  test('Cannot read a file with an invalid encoding', config('sync'), () => {
@@ -9,7 +9,7 @@ suite('Reading', () => {
9
9
  });
10
10
 
11
11
  test('Reading past the end of a file should not be an error', config('async'), async () => {
12
- const handle = await fs.promises.open('a.js', 'r');
12
+ await using handle = await fs.promises.open('a.js', 'r');
13
13
  const { bytesRead } = await handle.read(new Uint8Array(10), 0, 10, 10000);
14
14
  assert.equal(bytesRead, 0);
15
15
  });
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  suite('Rename', config('rename'), () => {
7
7
  /**
@@ -26,8 +26,8 @@ suite('Rename', config('rename'), () => {
26
26
  const subContents = await fs.promises.readdir(dir + '/_rename_me');
27
27
  assert.equal(subContents.length, 1);
28
28
 
29
- assert(await fs.promises.exists(dir + '/file.dat'));
30
- assert(await fs.promises.exists(dir + '/_rename_me/lol.txt'));
29
+ assert(await fs.promises.stat(dir + '/file.dat', { throwIfNoEntry: false }));
30
+ assert(await fs.promises.stat(dir + '/_rename_me/lol.txt', { throwIfNoEntry: false }));
31
31
  }
32
32
 
33
33
  test('rename directory', config('async'), async () => {
@@ -46,7 +46,7 @@ suite('Rename', config('rename'), () => {
46
46
 
47
47
  await check_directory(newDir);
48
48
 
49
- assert(!(await fs.promises.exists(oldDir)));
49
+ assert(!(await fs.promises.stat(oldDir, { throwIfNoEntry: false })));
50
50
 
51
51
  await fs.promises.mkdir(oldDir);
52
52
  await populate(oldDir);
@@ -67,7 +67,7 @@ suite('Rename', config('rename'), () => {
67
67
  await fs.promises.rename(one, two);
68
68
 
69
69
  assert.equal(await fs.promises.readFile(two, 'utf8'), 'hey');
70
- assert(!(await fs.promises.exists(one)));
70
+ assert(!(await fs.promises.stat(one, { throwIfNoEntry: false })));
71
71
  });
72
72
 
73
73
  test('File to Directory and Directory to File Rename', config('sync', 'async'), async () => {
@@ -2,7 +2,7 @@
2
2
  import { sync } from '@zenfs/core';
3
3
  import assert from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  const n_files = 130;
8
8
  const huge_size = 0x1000000;
@@ -1,8 +1,8 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
- import { defaultContext, hasAccess } from '@zenfs/core';
2
+ import { defaultContext, hasAccess, type Stats } from '@zenfs/core';
3
3
  import assert from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  suite('Stats', () => {
8
8
  const existing_file = 'x.txt';
@@ -35,7 +35,7 @@ suite('Stats', () => {
35
35
  fs.close(fd);
36
36
  });
37
37
 
38
- test('hasAccess for non-root access', config('sync', 'permissions'), () => {
38
+ test('hasAccess for non-root access', config('sync', 'permissions', 'root'), () => {
39
39
  const newFile = 'new.txt';
40
40
 
41
41
  fs.writeFileSync(newFile, 'hello', { mode: 0o640 });
@@ -72,6 +72,35 @@ suite('Stats', () => {
72
72
  Object.assign(defaultContext.credentials, prevCredentials);
73
73
  });
74
74
 
75
+ const missing = '/does-not-exist';
76
+
77
+ test('statSync throws for a missing entry', config('sync'), () => {
78
+ assert.throws(() => fs.statSync(missing), { code: 'ENOENT' });
79
+ assert.throws(() => fs.statSync(missing, { throwIfNoEntry: true }), { code: 'ENOENT' });
80
+ });
81
+
82
+ test('statSync with throwIfNoEntry: false', config('sync'), () => {
83
+ assert.equal(fs.statSync(missing, { throwIfNoEntry: false }), undefined);
84
+ assert.equal(fs.statSync(existing_file + '/nope', { throwIfNoEntry: false }), undefined);
85
+ });
86
+
87
+ test('lstatSync with throwIfNoEntry: false', config('sync'), () => {
88
+ assert.throws(() => fs.lstatSync(missing), { code: 'ENOENT' });
89
+ assert.equal(fs.lstatSync(missing, { throwIfNoEntry: false }), undefined);
90
+ });
91
+
92
+ test('stat with throwIfNoEntry: false', config('async'), async () => {
93
+ await assert.rejects(fs.promises.stat(missing), { code: 'ENOENT' });
94
+ assert.equal(await fs.promises.stat(missing, { throwIfNoEntry: false }), undefined);
95
+ assert.equal(await fs.promises.stat(existing_file + '/nope', { throwIfNoEntry: false }), undefined);
96
+ });
97
+
98
+ test('stat callback with throwIfNoEntry: false', config('async'), async () => {
99
+ const { promise, resolve, reject } = Promise.withResolvers<Stats | undefined>();
100
+ fs.stat(missing, { throwIfNoEntry: false }, (error, stats) => (error ? reject(error) : resolve(stats)));
101
+ assert.equal(await promise, undefined);
102
+ });
103
+
75
104
  test('stat file', config('async'), async () => {
76
105
  const stats = await fs.promises.stat(existing_file);
77
106
  assert(!stats.isDirectory());
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  // Top-level initialization
7
7
  const testFilePath = 'test-file.txt';
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import { test, suite } from 'node:test';
3
- import { config, fs } from '../common.js';
3
+ import { config, fs } from '../common.ts';
4
4
  import assert from 'node:assert/strict';
5
5
  import { basename } from 'node:path/posix';
6
6
 
@@ -4,7 +4,7 @@ import type { Exception } from 'kerium';
4
4
  import assert from 'node:assert/strict';
5
5
  import { suite, test } from 'node:test';
6
6
  import { wait } from 'utilium';
7
- import { config, fs } from '../common.js';
7
+ import { config, fs } from '../common.ts';
8
8
 
9
9
  const path = 'x.txt';
10
10
 
@@ -33,7 +33,7 @@ suite('Times', config('times'), () => {
33
33
  assert.deepEqual(unixTimestamps(await fs.promises.stat(path)), times);
34
34
 
35
35
  await fs.promises.utimes('foobarbaz', atime, mtime).catch((error: Exception) => {
36
- assert(error instanceof Error);
36
+ assert(Error.isError(error));
37
37
  assert.equal(error.code, 'ENOENT');
38
38
  });
39
39
 
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import assert from 'node:assert/strict';
3
3
  import { suite, test } from 'node:test';
4
- import { config, fs } from '../common.js';
4
+ import { config, fs } from '../common.ts';
5
5
 
6
6
  const path: string = 'truncate-file.txt',
7
7
  size = 1024 * 16,
@@ -2,7 +2,7 @@
2
2
  import type { Stats } from '@zenfs/core';
3
3
  import assert from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  const testDir = '/test-watch-dir';
8
8
  const testFile = testDir + '/test.txt';
@@ -3,8 +3,8 @@ import assert from 'node:assert/strict';
3
3
  import { readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path/posix';
5
5
  import { suite, test } from 'node:test';
6
- import { config, fs } from '../common.js';
7
- import { data as dataPath } from '../setup.js';
6
+ import { config, fs } from '../common.ts';
7
+ import { data as dataPath } from '../setup.ts';
8
8
 
9
9
  const fileName = 'write.txt';
10
10
  const utf8example = readFileSync(join(dataPath, 'utf8.txt'), 'utf8');
@@ -2,7 +2,7 @@
2
2
  import { Buffer } from 'buffer';
3
3
  import assert from 'node:assert/strict';
4
4
  import { suite, test } from 'node:test';
5
- import { config, fs } from '../common.js';
5
+ import { config, fs } from '../common.ts';
6
6
 
7
7
  suite('Extended Attributes', config('xattr'), () => {
8
8
  const testFile = 'xattr-test.txt';
@@ -2,11 +2,12 @@
2
2
  /* Run the FS test suite against native node:fs.
3
3
  Since the tests use absolute paths, everything is contained to a scratch directory using chroot-style path mapping. */
4
4
  import * as native from 'node:fs';
5
- import type { TestFlag, TestFlagState } from '../common.js';
5
+ import type { TestFlag, TestFlagState } from './common.ts';
6
6
  import { isAbsolute, join, relative, resolve } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
- import { copySync, data, tmp } from '../setup.js';
8
+ import { copySync, data, tmp } from './setup.ts';
9
9
  import { styleText } from 'node:util';
10
+ import { isRoot } from 'utilium/node';
10
11
 
11
12
  // The tests assume modes are used as-is, but native fs applies the process umask
12
13
  process.umask(0);
@@ -205,9 +206,6 @@ for (const [key, value] of Object.entries(native.promises)) {
205
206
  promises.watch = (...args: Parameters<typeof native.promises.watch>) =>
206
207
  native.promises.watch(...(mapArgs('watch', args) as Parameters<typeof native.promises.watch>));
207
208
 
208
- // ZenFS API extension
209
- promises.exists = (path: PathLike) => Promise.resolve(native.existsSync(toNative(path)));
210
-
211
209
  wrapped.promises = promises;
212
210
 
213
211
  export const fs = wrapped as unknown as typeof native;
@@ -220,6 +218,8 @@ export const flags: Partial<Record<TestFlag, TestFlagState>> = {
220
218
  lchmod: process.platform == 'darwin',
221
219
  // The suite uses ZenFS' own extended attribute API, which `node:fs` does not have
222
220
  xattr: false,
221
+ 'promises.exists': false,
222
+ root: isRoot || 'skip',
223
223
  };
224
224
 
225
225
  copySync(data, fs);
@@ -1,5 +1,5 @@
1
1
  import { fs as _fs, bindContext } from '@zenfs/core';
2
- import { copySync, data } from '../setup.js';
2
+ import { copySync, data } from '../setup.ts';
3
3
 
4
4
  _fs.mkdirSync('/new_root');
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { configureSingle, CopyOnWrite, fs, InMemory, resolveMountConfig } from '@zenfs/core';
2
- import { copySync, data } from '../setup.js';
2
+ import { copySync, data } from '../setup.ts';
3
3
 
4
4
  fs.umount('/');
5
5
  const readable = await resolveMountConfig({ backend: InMemory, label: 'ro' });
@@ -2,7 +2,7 @@ import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path/posix';
3
3
  import { configureSingle, CopyOnWrite, InMemory, InMemoryStore, mounts, Readonly, StoreFS } from '@zenfs/core';
4
4
  import { S_IFDIR } from '@zenfs/core/constants';
5
- import { copySync, data } from '../setup.js';
5
+ import { copySync, data } from '../setup.ts';
6
6
 
7
7
  copySync(data);
8
8
 
@@ -1,3 +1,3 @@
1
- import { copySync, data } from '../setup.js';
1
+ import { copySync, data } from '../setup.ts';
2
2
 
3
3
  copySync(data);
@@ -1,7 +1,7 @@
1
1
  import { InMemory, Port, configureSingle, fs, resolveMountConfig, resolveRemoteMount, sync } from '@zenfs/core';
2
2
  import { after, afterEach } from 'node:test';
3
3
  import { MessageChannel } from 'node:worker_threads';
4
- import { copySync, data } from '../setup.js';
4
+ import { copySync, data } from '../setup.ts';
5
5
 
6
6
  const { port1: localPort, port2: remotePort } = new MessageChannel();
7
7
 
@@ -1,5 +1,5 @@
1
1
  import { SingleBuffer, configureSingle } from '@zenfs/core';
2
- import { copySync, data } from '../setup.js';
2
+ import { copySync, data } from '../setup.ts';
3
3
 
4
4
  await configureSingle({
5
5
  backend: SingleBuffer,
package/tests/setup.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import { fs as _fs } from '@zenfs/core';
3
+ import type { NodeFS } from '@zenfs/core/node/types';
3
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
4
5
  import { join, relative } from 'node:path';
5
- import type { NodeFS } from '@zenfs/core/node/types.js';
6
6
 
7
7
  export const data = join(import.meta.dirname, 'data');
8
8
 
@@ -7,7 +7,8 @@
7
7
  "esModuleInterop": true,
8
8
  "allowSyntheticDefaultImports": true,
9
9
  "allowJs": true,
10
- "rootDir": ".."
10
+ "rootDir": "..",
11
+ "allowImportingTsExtensions": true
11
12
  },
12
13
  "include": ["**/*.ts", "*.ts", "**/*.js", "../types/uint8array.d.ts"]
13
14
  }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- sudo npx zenfs-test -v tests/native/setup.ts