@zenfs/core 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/COPYING.md +18 -0
  2. package/{readme.md → README.md} +16 -74
  3. package/dist/backends/fetch.js +1 -1
  4. package/dist/backends/memory.js +1 -1
  5. package/dist/backends/passthrough.d.ts +1 -2
  6. package/dist/backends/single_buffer.js +1 -1
  7. package/dist/backends/store/fs.js +4 -4
  8. package/dist/config.js +15 -15
  9. package/dist/context.js +3 -2
  10. package/dist/index.d.ts +9 -3
  11. package/dist/index.js +9 -4
  12. package/dist/internal/contexts.d.ts +5 -4
  13. package/dist/internal/devices.js +1 -1
  14. package/dist/internal/error.d.ts +11 -2
  15. package/dist/internal/error.js +38 -2
  16. package/dist/internal/file_index.js +1 -1
  17. package/dist/internal/index.d.ts +1 -0
  18. package/dist/internal/index.js +2 -1
  19. package/dist/internal/index_fs.js +1 -1
  20. package/dist/internal/inode.d.ts +51 -2
  21. package/dist/internal/inode.js +18 -2
  22. package/dist/mixins/shared.js +1 -1
  23. package/dist/node/async.d.ts +278 -0
  24. package/dist/node/async.js +518 -0
  25. package/dist/node/compat.d.ts +4 -0
  26. package/dist/node/compat.js +6 -0
  27. package/dist/node/dir.d.ts +78 -0
  28. package/dist/node/dir.js +150 -0
  29. package/dist/node/index.d.ts +8 -0
  30. package/dist/node/index.js +8 -0
  31. package/dist/{vfs → node}/promises.d.ts +10 -66
  32. package/dist/{vfs → node}/promises.js +141 -478
  33. package/dist/{vfs → node}/stats.d.ts +0 -4
  34. package/dist/{vfs → node}/stats.js +1 -16
  35. package/dist/{vfs → node}/streams.js +2 -2
  36. package/dist/node/sync.d.ts +252 -0
  37. package/dist/node/sync.js +682 -0
  38. package/dist/node/types.d.ts +21 -0
  39. package/dist/path.js +3 -25
  40. package/dist/utils.d.ts +1 -7
  41. package/dist/utils.js +0 -6
  42. package/dist/vfs/acl.js +1 -1
  43. package/dist/vfs/async.d.ts +22 -278
  44. package/dist/vfs/async.js +212 -501
  45. package/dist/vfs/dir.d.ts +5 -82
  46. package/dist/vfs/dir.js +5 -233
  47. package/dist/vfs/file.d.ts +52 -13
  48. package/dist/vfs/file.js +167 -25
  49. package/dist/vfs/flags.js +1 -1
  50. package/dist/vfs/index.d.ts +2 -5
  51. package/dist/vfs/index.js +2 -5
  52. package/dist/vfs/shared.d.ts +25 -1
  53. package/dist/vfs/shared.js +6 -4
  54. package/dist/vfs/sync.d.ts +17 -245
  55. package/dist/vfs/sync.js +129 -773
  56. package/dist/vfs/watchers.d.ts +1 -1
  57. package/dist/vfs/watchers.js +2 -2
  58. package/dist/vfs/xattr.js +1 -1
  59. package/eslint.shared.js +1 -0
  60. package/package.json +7 -5
  61. package/scripts/make-index.js +5 -29
  62. package/scripts/test.js +59 -51
  63. package/tests/backend/fetch.test.ts +2 -2
  64. package/tests/backend/port.test.ts +2 -3
  65. package/tests/backend/single-buffer.test.ts +1 -1
  66. package/tests/common/casefold.test.ts +1 -1
  67. package/tests/common/context.test.ts +11 -4
  68. package/tests/common/devices.test.ts +3 -3
  69. package/tests/common/handle.test.ts +4 -3
  70. package/tests/common/inode.test.ts +2 -2
  71. package/tests/common/mounts.test.ts +1 -3
  72. package/tests/common/mutex.test.ts +1 -3
  73. package/tests/common/path.test.ts +2 -2
  74. package/tests/common/readline.test.ts +1 -1
  75. package/tests/common.ts +5 -4
  76. package/tests/fetch/fetch.ts +1 -1
  77. package/tests/fs/dir.test.ts +3 -43
  78. package/tests/fs/directory.test.ts +4 -4
  79. package/tests/fs/errors.test.ts +2 -2
  80. package/tests/fs/links.test.ts +1 -1
  81. package/tests/fs/permissions.test.ts +3 -3
  82. package/tests/fs/read.test.ts +1 -1
  83. package/tests/fs/scaling.test.ts +1 -1
  84. package/tests/fs/stat.test.ts +1 -2
  85. package/tests/fs/times.test.ts +1 -1
  86. package/tests/fs/watch.test.ts +3 -2
  87. package/tests/setup/context.ts +1 -2
  88. package/tests/setup/cow.ts +1 -1
  89. package/tests/setup/index.ts +2 -2
  90. package/tests/setup/port.ts +1 -1
  91. package/tests/setup/single-buffer.ts +1 -1
  92. package/tests/setup.ts +4 -3
  93. package/dist/vfs/types.d.ts +0 -24
  94. package/tests/assignment.ts +0 -21
  95. /package/dist/{vfs/constants.d.ts → constants.d.ts} +0 -0
  96. /package/dist/{vfs/constants.js → constants.js} +0 -0
  97. /package/dist/{readline.d.ts → node/readline.d.ts} +0 -0
  98. /package/dist/{readline.js → node/readline.js} +0 -0
  99. /package/dist/{vfs → node}/streams.d.ts +0 -0
  100. /package/dist/{vfs → node}/types.js +0 -0
@@ -2,7 +2,7 @@ import type { EventEmitter as NodeEventEmitter } from 'node:events';
2
2
  import type * as fs from 'node:fs';
3
3
  import type { V_Context } from '../context.js';
4
4
  import { EventEmitter } from 'eventemitter3';
5
- import { type Stats } from './stats.js';
5
+ import { type Stats } from '../node/stats.js';
6
6
  /**
7
7
  * Base class for file system watchers.
8
8
  * Provides event handling capabilities for watching file system changes.
@@ -2,8 +2,8 @@ import { EventEmitter } from 'eventemitter3';
2
2
  import { UV } from 'kerium';
3
3
  import { basename, dirname, join, relative } from '../path.js';
4
4
  import { normalizePath } from '../utils.js';
5
- import { isStatsEqual } from './stats.js';
6
- import { statSync } from './sync.js';
5
+ import { isStatsEqual } from '../node/stats.js';
6
+ import { statSync } from '../node/sync.js';
7
7
  /**
8
8
  * Base class for file system watchers.
9
9
  * Provides event handling capabilities for watching file system changes.
package/dist/vfs/xattr.js CHANGED
@@ -4,7 +4,7 @@ import { rethrow, setUVMessage, UV } from 'kerium';
4
4
  import { Attributes, hasAccess } from '../internal/inode.js';
5
5
  import { normalizePath } from '../utils.js';
6
6
  import { checkAccess } from './config.js';
7
- import { R_OK, W_OK } from './constants.js';
7
+ import { R_OK, W_OK } from '../constants.js';
8
8
  import { resolveMount } from './shared.js';
9
9
  const _allowedRestrictedNames = [];
10
10
  /**
package/eslint.shared.js CHANGED
@@ -46,6 +46,7 @@ export default [
46
46
  '@typescript-eslint/restrict-plus-operands': 'off',
47
47
  '@typescript-eslint/no-base-to-string': 'off',
48
48
  '@typescript-eslint/no-unused-expressions': 'warn',
49
+ '@typescript-eslint/no-empty-object-type': 'off',
49
50
  },
50
51
  },
51
52
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -45,8 +45,10 @@
45
45
  "exports": {
46
46
  ".": "./dist/index.js",
47
47
  "./*": "./dist/*",
48
- "./emulation/*": "./dist/vfs/*",
49
- "./promises": "./dist/vfs/promises.js",
48
+ "./emulation/*": "./dist/node/*",
49
+ "./promises": "./dist/node/promises.js",
50
+ "./readline": "./dist/node/readline.js",
51
+ "./constants": "./dist/constants.js",
50
52
  "./path": "./dist/path.js",
51
53
  "./eslint": "./eslint.shared.js",
52
54
  "./tests/*": "./tests/*",
@@ -65,7 +67,7 @@
65
67
  "test": "npx zenfs-test --clean; npx zenfs-test -abcp; tests/fetch/run.sh; npx zenfs-test --report",
66
68
  "build": "tsc -p tsconfig.json",
67
69
  "build:docs": "typedoc",
68
- "dev": "npm run build -- --watch",
70
+ "dev": "tsc -p tsconfig.json --watch",
69
71
  "prepublishOnly": "npm run build"
70
72
  },
71
73
  "dependencies": {
@@ -73,7 +75,7 @@
73
75
  "buffer": "^6.0.3",
74
76
  "eventemitter3": "^5.0.1",
75
77
  "kerium": "^1.3.4",
76
- "memium": "^0.3.7",
78
+ "memium": "^0.3.10",
77
79
  "readable-stream": "^4.5.2",
78
80
  "utilium": "^2.5.0"
79
81
  },
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { readdirSync, statSync, writeFileSync } from 'node:fs';
3
3
  import { matchesGlob, relative, join, resolve } from 'node:path/posix';
4
- import { parseArgs } from 'node:util';
4
+ import { parseArgs, styleText } from 'node:util';
5
5
 
6
6
  const { values: options, positionals } = parseArgs({
7
7
  options: {
@@ -42,36 +42,12 @@ function fixSlash(path) {
42
42
 
43
43
  const resolvedRoot = root || '.';
44
44
 
45
- const colors = {
46
- reset: 0,
47
- black: 30,
48
- red: 31,
49
- green: 32,
50
- yellow: 33,
51
- blue: 34,
52
- magenta: 35,
53
- cyan: 36,
54
- white: 37,
55
- bright_black: 90,
56
- bright_red: 91,
57
- bright_green: 92,
58
- bright_yellow: 93,
59
- bright_blue: 94,
60
- bright_magenta: 95,
61
- bright_cyan: 96,
62
- bright_white: 97,
63
- };
64
-
65
- function color(color, text) {
66
- return `\x1b[${colors[color]}m${text}\x1b[0m`;
67
- }
68
-
69
45
  const entries = new Map();
70
46
 
71
47
  function computeEntries(path) {
72
48
  try {
73
49
  if (options.ignore.some(pattern => matchesGlob(path, pattern))) {
74
- if (!options.quiet) console.log(`${color('yellow', 'skip')} ${path}`);
50
+ if (!options.quiet) console.log(`${styleText('yellow', 'skip')} ${path}`);
75
51
  return;
76
52
  }
77
53
 
@@ -80,7 +56,7 @@ function computeEntries(path) {
80
56
  if (stats.isFile()) {
81
57
  entries.set('/' + relative(resolvedRoot, path), stats);
82
58
  if (options.verbose) {
83
- console.log(`${color('green', 'file')} ${path}`);
59
+ console.log(`${styleText('green', 'file')} ${path}`);
84
60
  }
85
61
  return;
86
62
  }
@@ -90,11 +66,11 @@ function computeEntries(path) {
90
66
  }
91
67
  entries.set('/' + relative(resolvedRoot, path), stats);
92
68
  if (options.verbose) {
93
- console.log(`${color('bright_green', ' dir')} ${path}`);
69
+ console.log(`${styleText('greenBright', ' dir')} ${path}`);
94
70
  }
95
71
  } catch (e) {
96
72
  if (!options.quiet) {
97
- console.log(`${color('red', 'fail')} ${path}: ${e.message}`);
73
+ console.log(`${styleText('red', 'fail')} ${path}: ${e.message}`);
98
74
  }
99
75
  }
100
76
  }
package/scripts/test.js CHANGED
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  import { execSync } from 'node:child_process';
4
3
  import { existsSync, globSync, mkdirSync, rmSync } from 'node:fs';
5
4
  import { join, parse, basename } from 'node:path';
6
- import { parseArgs } from 'node:util';
5
+ import { parseArgs, styleText } from 'node:util';
7
6
 
8
7
  const { values: options, positionals } = parseArgs({
9
8
  options: {
@@ -14,6 +13,7 @@ const { values: options, positionals } = parseArgs({
14
13
  log: { short: 'l', type: 'string', default: '' },
15
14
  'file-names': { short: 'N', type: 'boolean', default: false },
16
15
  ci: { short: 'C', type: 'boolean', default: false },
16
+ debug: { short: 'd', type: 'boolean', default: false },
17
17
 
18
18
  // Test behavior
19
19
  test: { short: 't', type: 'string' },
@@ -25,15 +25,20 @@ const { values: options, positionals } = parseArgs({
25
25
  skip: { short: 's', type: 'string', multiple: true, default: [] },
26
26
  'exit-on-fail': { short: 'e', type: 'boolean' },
27
27
 
28
- // Coverage
28
+ // Coverage and performance
29
29
  coverage: { type: 'string', default: 'tests/.coverage' },
30
30
  preserve: { short: 'p', type: 'boolean' },
31
31
  report: { type: 'boolean', default: false },
32
32
  clean: { type: 'boolean', default: false },
33
+ profile: { type: 'boolean', default: false },
33
34
  },
34
35
  allowPositionals: true,
35
36
  });
36
37
 
38
+ function debug(...args) {
39
+ if (options.debug) console.debug(styleText('dim', '[debug]'), ...args.map(a => (typeof a === 'string' ? styleText('dim', a) : a)));
40
+ }
41
+
37
42
  if (options.help) {
38
43
  console.log(`zenfs-test [...options] <...paths>
39
44
 
@@ -47,22 +52,24 @@ Behavior:
47
52
  -t, --test <glob> Which FS test suite(s) to run
48
53
  -f, --force Whether to use --test-force-exit
49
54
  -I, --inspect Use the inspector for debugging
50
- -s, --skip <pattern> Skip tests with names matching the given pattern. Can be specified multiple times.
55
+ -s, --skip <pattern> Skip tests with names matching the given pattern. Can be specified multiple times.
56
+ -d, --debug Output debug messages from the test runner
51
57
 
52
58
  Output:
53
- -h, --help Outputs this help message
54
- -v, --verbose Output verbose messages
55
- -q, --quiet Don't output normal messages
56
- -l, --logs <level> Change the default log level for test output. Level can be a number or string
57
- -N, --file-names Use full file paths for tests from setup files instead of the base name
58
- -C, --ci Continuous integration (CI) mode. This interacts with the Github
59
- Checks API for better test status. Requires @octokit/action
59
+ -h, --help Outputs this help message
60
+ -v, --verbose Output verbose messages
61
+ -q, --quiet Don't output normal messages
62
+ -l, --logs <level> Change the default log level for test output. Level can be a number or string
63
+ -N, --file-names Use full file paths for tests from setup files instead of the base name
64
+ -C, --ci Continuous integration (CI) mode. This interacts with the Github
65
+ Checks API for better test status. Requires @octokit/action
60
66
 
61
67
  Coverage:
62
- --coverage <dir> Override the default coverage data directory
63
- -p, --preserve Do not delete or report coverage data
64
- --report ONLY report coverage
65
- --clean ONLY clean up coverage directory`);
68
+ --coverage <dir> Override the default coverage data directory
69
+ -p, --preserve Do not delete or report coverage data
70
+ --report ONLY report coverage
71
+ --clean ONLY clean up coverage directory
72
+ --profile Record performance profiles`);
66
73
  process.exit();
67
74
  }
68
75
 
@@ -73,6 +80,7 @@ if (options.quiet && options.verbose) {
73
80
 
74
81
  process.env.NODE_V8_COVERAGE = options.coverage;
75
82
  process.env.ZENFS_LOG_LEVEL = options.log;
83
+ if (options.verbose) process.env.VERBOSE = '1';
76
84
 
77
85
  if (options.clean) {
78
86
  rmSync(options.coverage, { recursive: true, force: true });
@@ -117,16 +125,6 @@ if (options.auto) {
117
125
  !options.quiet && console.log(`Auto-detected ${sum} test setup files`);
118
126
  }
119
127
 
120
- /**
121
- * Colorizes some text
122
- * @param {string} text Text to color
123
- * @param {string | number} code ANSI escape code
124
- * @returns
125
- */
126
- function color(text, code) {
127
- return `\x1b[${code}m${text}\x1b[0m`;
128
- }
129
-
130
128
  async function status(name) {
131
129
  const start = performance.now();
132
130
 
@@ -141,22 +139,22 @@ async function status(name) {
141
139
  unit = 's';
142
140
  }
143
141
 
144
- return color(`(${delta} ${unit})`, '2;37');
142
+ return styleText('dim', `(${delta} ${unit})`);
145
143
  };
146
144
 
147
145
  const maybeName = options.verbose ? `: ${name}` : '';
148
146
 
149
147
  return {
150
148
  async pass() {
151
- if (!options.quiet) console.log(`${color('passed', 32)}${maybeName} ${time()}`);
149
+ if (!options.quiet) console.log(`${styleText('green', 'passed')}${maybeName} ${time()}`);
152
150
  if (options.ci) await ci.completeCheck(name, 'success');
153
151
  },
154
152
  async skip() {
155
- if (!options.quiet) console.log(`${color('skipped', 33)}${maybeName} ${time()}`);
153
+ if (!options.quiet) console.log(`${styleText('yellow', 'skipped')}${maybeName} ${time()}`);
156
154
  if (options.ci) await ci.completeCheck(name, 'skipped');
157
155
  },
158
156
  async fail() {
159
- console.error(`${color('failed', '1;31')}${maybeName} ${time()}`);
157
+ console.error(`${styleText(['red', 'bold'], 'failed')}${maybeName} ${time()}`);
160
158
  if (options.ci) await ci.completeCheck(name, 'failure');
161
159
  process.exitCode = 1;
162
160
  if (options['exit-on-fail']) process.exit();
@@ -167,16 +165,36 @@ async function status(name) {
167
165
  if (!options.preserve) rmSync(options.coverage, { force: true, recursive: true });
168
166
  mkdirSync(options.coverage, { recursive: true });
169
167
 
168
+ /**
169
+ * Generate the command used to run the tests
170
+ */
171
+ function makeCommand(profileName, ...rest) {
172
+ const command = [
173
+ 'tsx --trace-deprecation',
174
+ options.inspect ? '--inspect' : '',
175
+ '--test --experimental-test-coverage',
176
+ options.force ? '--test-force-exit' : '',
177
+ options.skip.length ? `--test-skip-pattern='${options.skip.join('|').replaceAll("'", "\\'")}'` : '',
178
+ !options.profile ? '' : `--cpu-prof --cpu-prof-dir=.profiles --cpu-prof-name=${profileName}.cpuprofile --cpu-prof-interval=500`,
179
+ ...rest,
180
+ ]
181
+ .filter(v => v)
182
+ .join(' ');
183
+
184
+ if (!options.quiet) debug('command:', command);
185
+
186
+ return command;
187
+ }
188
+
170
189
  if (options.common) {
171
- !options.quiet && process.stdout.write('Running common tests...' + (options.verbose ? '\n' : ' '));
190
+ const command = makeCommand('common', `'tests/*.test.ts' 'tests/**/!(fs)/*.test.ts'`);
191
+
192
+ if (!options.quiet) process.stdout.write('Running common tests...' + (options.verbose ? '\n' : ' '));
172
193
  const { pass, fail } = await status('Common tests');
173
194
  try {
174
- execSync(
175
- `tsx ${options.inspect ? 'inspect' : ''} ${options.force ? '--test-force-exit' : ''} --test --experimental-test-coverage 'tests/*.test.ts' 'tests/**/!(fs)/*.test.ts'`,
176
- {
177
- stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
178
- }
179
- );
195
+ execSync(command, {
196
+ stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
197
+ });
180
198
  await pass();
181
199
  } catch {
182
200
  await fail();
@@ -192,10 +210,11 @@ for (const setupFile of positionals) {
192
210
  }
193
211
 
194
212
  process.env.SETUP = setupFile;
195
- process.env.VERBOSE = +options.verbose;
196
213
 
197
214
  const name = options['file-names'] && !options.ci ? setupFile : parse(setupFile).name;
198
215
 
216
+ const command = makeCommand(name, `'${testsGlob.replaceAll("'", "\\'")}'`, process.env.CMD);
217
+
199
218
  if (!options.quiet) {
200
219
  if (options.verbose) console.log('Running tests:', name);
201
220
  else process.stdout.write(`Running tests: ${name}... `);
@@ -209,20 +228,9 @@ for (const setupFile of positionals) {
209
228
  }
210
229
 
211
230
  try {
212
- execSync(
213
- [
214
- 'tsx --trace-deprecation',
215
- options.inspect ? '--inspect' : '',
216
- '--test --experimental-test-coverage',
217
- options.force ? '--test-force-exit' : '',
218
- options.skip.length ? `--test-skip-pattern='${options.skip.join('|').replaceAll("'", "\\'")}'` : '',
219
- `'${testsGlob.replaceAll("'", "\\'")}'`,
220
- process.env.CMD,
221
- ].join(' '),
222
- {
223
- stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
224
- }
225
- );
231
+ execSync(command, {
232
+ stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
233
+ });
226
234
  await pass();
227
235
  } catch {
228
236
  await fail();
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { Fetch, configureSingle, fs, mounts, type FetchFS } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
3
4
  import { join } from 'node:path';
4
5
  import { after, suite, test } from 'node:test';
5
6
  import { Worker } from 'node:worker_threads';
6
- import { Fetch, configureSingle, fs, mounts, type FetchFS } from '../../dist/index.js';
7
7
  import { baseUrl, defaultEntries, indexPath, whenServerReady } from '../fetch/config.js';
8
8
  import { setupLogs } from '../logs.js';
9
9
 
@@ -42,7 +42,7 @@ suite('Fetch with `disableAsyncCache`', () => {
42
42
  assert.deepEqual(entries, [...defaultEntries, 'example', 'duck']);
43
43
  });
44
44
 
45
- test('Uncached synchronous operations throw', async () => {
45
+ test('Uncached synchronous operations throw', () => {
46
46
  assert.throws(() => fs.readFileSync('/x.txt', 'utf8'), { code: 'EAGAIN' });
47
47
  });
48
48
  });
@@ -1,10 +1,9 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import type { InMemoryStore, StoreFS } from '@zenfs/core';
3
+ import { InMemory, Port, attachFS, configure, configureSingle, fs, resolveMountConfig, waitOnline } from '@zenfs/core';
2
4
  import assert from 'node:assert/strict';
3
5
  import { after, suite, test } from 'node:test';
4
6
  import { MessageChannel, Worker } from 'node:worker_threads';
5
- import { Port, attachFS } from '../../dist/backends/port.js';
6
- import type { InMemoryStore, StoreFS } from '../../dist/index.js';
7
- import { InMemory, configure, configureSingle, fs, resolveMountConfig, waitOnline } from '../../dist/index.js';
8
7
  import { setupLogs } from '../logs.js';
9
8
  setupLogs();
10
9
 
@@ -2,7 +2,7 @@
2
2
  import assert from 'node:assert';
3
3
  import { suite, test } from 'node:test';
4
4
  import { Worker } from 'worker_threads';
5
- import { fs, mount, resolveMountConfig, SingleBuffer } from '../../dist/index.js';
5
+ import { fs, mount, resolveMountConfig, SingleBuffer } from '@zenfs/core';
6
6
  import { setupLogs } from '../logs.js';
7
7
 
8
8
  setupLogs();
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { configure, fs, mounts } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
3
4
  import { suite, test } from 'node:test';
4
- import { mounts, configure, fs } from '../../dist/index.js';
5
5
 
6
6
  suite('Case folding', () => {
7
7
  test('Configuration', async () => {
@@ -1,13 +1,12 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { bindContext, configure, fs, InMemory } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
3
4
  import { suite, test } from 'node:test';
4
5
  import { canary } from 'utilium';
5
- import { bindContext } from '../../dist/context.js';
6
- import * as fs from '../../dist/vfs/index.js';
7
- import { configure, InMemory } from '../../dist/index.js';
8
6
 
9
7
  fs.mkdirSync('/ctx');
10
- const { fs: ctx } = bindContext({ root: '/ctx' });
8
+ const context = bindContext({ root: '/ctx' });
9
+ const ctx = context.fs;
11
10
 
12
11
  suite('Context', () => {
13
12
  test('create a file', () => {
@@ -73,4 +72,12 @@ suite('Context', () => {
73
72
 
74
73
  assert.deepEqual(bananas.fs.readdirSync('/'), ['yellow']);
75
74
  });
75
+
76
+ test('Different working directory', { todo: true }, () => {
77
+ // @zenfs/core#263
78
+ ctx.mkdirSync('/test');
79
+ context.pwd = '/test';
80
+
81
+ assert.equal(ctx.realpathSync('.'), '/test');
82
+ });
76
83
  });
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
2
  import { suite, test } from 'node:test';
3
3
  import assert from 'node:assert/strict';
4
- import { configure } from '../../dist/config.js';
5
- import * as fs from '../../dist/vfs/index.js';
6
- import { S_IFCHR, S_IFMT } from '../../dist/vfs/constants.js';
4
+ import { configure } from '@zenfs/core';
5
+ import { fs } from '@zenfs/core';
6
+ import { S_IFCHR, S_IFMT } from '@zenfs/core/constants';
7
7
 
8
8
  await configure({
9
9
  addDevices: true,
@@ -1,13 +1,14 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { constants, promises } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
4
+ import type { FileHandle } from 'node:fs/promises';
3
5
  import { after, suite, test } from 'node:test';
4
6
  import { wait } from 'utilium';
5
- import { constants, type FileHandle, open } from '../../dist/vfs/promises.js';
6
7
 
7
8
  const content = 'The cake is a lie',
8
9
  appended = '\nAnother lie';
9
10
 
10
- const handle: FileHandle = await open('./test.txt', 'ws+');
11
+ const handle: FileHandle = await promises.open('./test.txt', 'ws+');
11
12
 
12
13
  suite('FileHandle', () => {
13
14
  test('writeFile', async () => {
@@ -54,7 +55,7 @@ suite('FileHandle', () => {
54
55
  test('readLines', async () => {
55
56
  await handle.writeFile('first line\nsecond line\nthird line');
56
57
 
57
- await using rl = handle.readLines();
58
+ using rl = handle.readLines();
58
59
 
59
60
  const lines: string[] = [];
60
61
  rl.on('line', (line: string) => lines.push(line));
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
- import { suite, test } from 'node:test';
3
- import { Inode } from '../../dist/internal/inode.js';
2
+ import { Inode } from '@zenfs/core';
4
3
  import assert from 'node:assert';
4
+ import { suite, test } from 'node:test';
5
5
 
6
6
  suite('Inode manipulation', () => {
7
7
  const inode = new Inode();
@@ -1,9 +1,7 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { configure, fs, InMemory, mounts } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
3
4
  import { suite, test } from 'node:test';
4
- import { configure } from '../../dist/config.js';
5
- import * as fs from '../../dist/vfs/index.js';
6
- import { InMemory, mounts } from '../../dist/index.js';
7
5
 
8
6
  suite('Mounts', () => {
9
7
  test('Mount in nested directory', async () => {
@@ -1,10 +1,8 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { InMemoryStore, Mutexed, StoreFS } from '@zenfs/core';
2
3
  import assert from 'node:assert/strict';
3
4
  import { suite, test } from 'node:test';
4
5
  import { wait } from 'utilium';
5
- import { InMemoryStore } from '../../dist/backends/memory.js';
6
- import { StoreFS } from '../../dist/backends/store/fs.js';
7
- import { Mutexed } from '../../dist/mixins/mutexed.js';
8
6
 
9
7
  suite('Mutexed FS', () => {
10
8
  const fs = new (Mutexed(StoreFS))(new InMemoryStore(0x10000, 'test'));
@@ -1,8 +1,8 @@
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 { basename, dirname, extname, join, normalize, resolve } from '../../dist/path.js';
5
- import * as fs from '../../dist/vfs/index.js';
4
+ import { basename, dirname, extname, join, normalize, resolve } from '@zenfs/core/path';
5
+ import { fs } from '@zenfs/core';
6
6
 
7
7
  suite('Path emulation', () => {
8
8
  test('resolve', () => {
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { createInterface, Interface } from '@zenfs/core/readline';
2
3
  import assert from 'node:assert/strict';
3
4
  import { PassThrough } from 'node:stream';
4
5
  import { suite, test } from 'node:test';
5
6
  import { wait } from 'utilium';
6
- import { createInterface, Interface } from '../../dist/readline.js';
7
7
 
8
8
  suite('Readline interface', { skip: true }, () => {
9
9
  test('creates interface with readable stream', async () => {
package/tests/common.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { fs as defaultFS } from '@zenfs/core';
3
+ import type { NodeFS } from '@zenfs/core/node/types.js';
2
4
  import { join, resolve } from 'node:path';
3
- import { fs as defaultFS } from '../dist/index.js';
4
- import { setupLogs } from './logs.js';
5
5
  import { styleText } from 'node:util';
6
- export type * from '../dist/index.js';
6
+ import { setupLogs } from './logs.js';
7
7
 
8
8
  setupLogs();
9
9
 
@@ -18,4 +18,5 @@ const setup = await import(setupPath).catch(error => {
18
18
  throw error;
19
19
  });
20
20
 
21
- export const fs = (setup.fs || defaultFS) as typeof defaultFS;
21
+ // Satisfies is used to make sure that ZenFS is fully type compatible with Node.js
22
+ export const fs = (setup.fs || defaultFS) as typeof defaultFS satisfies NodeFS;
@@ -1,5 +1,5 @@
1
+ import { configure, Fetch } from '@zenfs/core';
1
2
  import { log } from 'kerium';
2
- import { configure, Fetch } from '../../dist/index.js';
3
3
  import { baseUrl } from './config.js';
4
4
 
5
5
  await configure({
@@ -1,7 +1,8 @@
1
1
  // SPDX-License-Identifier: LGPL-3.0-or-later
2
+ import { sync, type Dirent } from '@zenfs/core';
2
3
  import assert, { rejects } from 'node:assert/strict';
3
4
  import { suite, test } from 'node:test';
4
- import { fs, type Dirent } from '../common.js';
5
+ import { fs } from '../common.js';
5
6
 
6
7
  const testFile = 'test-file.txt';
7
8
  fs.writeFileSync(testFile, 'Sample content');
@@ -13,48 +14,7 @@ fs.mkdirSync(testDirPath);
13
14
  for (const file of testFiles) {
14
15
  fs.writeFileSync(`${testDirPath}/${file}`, 'Sample content');
15
16
  }
16
-
17
- suite('Dirent', () => {
18
- test('name and parentPath getters', async () => {
19
- const stats = await fs.promises.lstat(testFile);
20
- const dirent = fs.Dirent.from(testFile, stats);
21
-
22
- assert.equal(dirent.name, testFile);
23
- assert.equal(dirent.parentPath, '.');
24
- });
25
-
26
- test('isFile', async () => {
27
- const fileStats = await fs.promises.lstat(testFile);
28
- const fileDirent = fs.Dirent.from(testFile, fileStats);
29
-
30
- assert(fileDirent.isFile());
31
- assert(!fileDirent.isDirectory());
32
- });
33
-
34
- test('isDirectory', async () => {
35
- const dirStats = await fs.promises.lstat('test-directory');
36
- const dirDirent = fs.Dirent.from('test-directory', dirStats);
37
-
38
- assert(!dirDirent.isFile());
39
- assert(dirDirent.isDirectory());
40
- });
41
-
42
- test('isSymbolicLink', async () => {
43
- const symlinkStats = await fs.promises.lstat('test-symlink');
44
- const symlinkDirent = fs.Dirent.from('test-symlink', symlinkStats);
45
-
46
- assert(symlinkDirent.isSymbolicLink());
47
- });
48
-
49
- test('other methods return false', async () => {
50
- const fileStats = await fs.promises.lstat(testFile);
51
- const fileDirent = fs.Dirent.from(testFile, fileStats);
52
-
53
- assert(!fileDirent.isBlockDevice());
54
- assert(!fileDirent.isCharacterDevice());
55
- assert(!fileDirent.isSocket());
56
- });
57
- });
17
+ await sync();
58
18
 
59
19
  suite('Dir', () => {
60
20
  test('read()', async () => {
@@ -29,7 +29,7 @@ suite('Directories', () => {
29
29
  test('mkdirSync', async () => await fs.promises.mkdir('/two', 0o000));
30
30
 
31
31
  test('mkdir, nested', async () => {
32
- await assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested' });
32
+ await assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested/dir' });
33
33
  assert(!(await fs.promises.exists('/nested/dir')));
34
34
  });
35
35
 
@@ -148,9 +148,9 @@ suite('Directories', () => {
148
148
  entries.sort((a, b) => join(a.parentPath, a.name).localeCompare(join(b.parentPath, b.name)));
149
149
  const values = entries.map(entry => [entry.parentPath, entry.name]);
150
150
 
151
- assert.deepEqual(values[0], [testDir, 'file1.txt']);
152
- assert.deepEqual(values[4], [join(testDir, 'subdir1'), 'file4.txt']);
153
- assert.deepEqual(values[8], [join(testDir, 'subdir2'), 'file5.txt']);
151
+ assert.deepEqual(values[0], ['.', 'file1.txt']);
152
+ assert.deepEqual(values[4], ['subdir1', 'file4.txt']);
153
+ assert.deepEqual(values[8], ['subdir2', 'file5.txt']);
154
154
  });
155
155
 
156
156
  test('readdirSync returns files recursively', () => {