mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
Adds the node:vfs builtin module with VirtualFileSystem and provider classes. No integration with fs, modules, or SEA. Assisted-by: Claude-Opus4.7 Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: https://github.com/nodejs/node/pull/63115 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
115 lines
3.0 KiB
JavaScript
115 lines
3.0 KiB
JavaScript
// Flags: --experimental-vfs
|
|
'use strict';
|
|
|
|
// Exercise the VirtualDir handle returned by opendirSync.
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const vfs = require('node:vfs');
|
|
|
|
const myVfs = vfs.create();
|
|
myVfs.mkdirSync('/d');
|
|
myVfs.writeFileSync('/d/a.txt', 'a');
|
|
myVfs.writeFileSync('/d/b.txt', 'b');
|
|
myVfs.mkdirSync('/d/sub');
|
|
|
|
// readSync iteration
|
|
{
|
|
const dir = myVfs.opendirSync('/d');
|
|
assert.strictEqual(dir.path, '/d');
|
|
const names = [];
|
|
let entry;
|
|
while ((entry = dir.readSync()) !== null) {
|
|
names.push(entry.name);
|
|
}
|
|
assert.deepStrictEqual(names.sort(), ['a.txt', 'b.txt', 'sub']);
|
|
dir.closeSync();
|
|
// Closing again must throw
|
|
assert.throws(() => dir.closeSync(), { code: 'ERR_DIR_CLOSED' });
|
|
// Reading after close throws
|
|
assert.throws(() => dir.readSync(), { code: 'ERR_DIR_CLOSED' });
|
|
}
|
|
|
|
// for-await iteration
|
|
(async () => {
|
|
const dir = myVfs.opendirSync('/d');
|
|
const names = [];
|
|
for await (const entry of dir) {
|
|
names.push(entry.name);
|
|
}
|
|
assert.deepStrictEqual(names.sort(), ['a.txt', 'b.txt', 'sub']);
|
|
})().then(common.mustCall());
|
|
|
|
// Async read with callback
|
|
(async () => {
|
|
const dir = myVfs.opendirSync('/d');
|
|
await new Promise((resolve, reject) => {
|
|
dir.read((err, entry) => {
|
|
if (err) reject(err);
|
|
else resolve(entry);
|
|
});
|
|
});
|
|
await new Promise((resolve, reject) => {
|
|
dir.close((err) => {
|
|
if (err) reject(err);
|
|
else resolve();
|
|
});
|
|
});
|
|
})().then(common.mustCall());
|
|
|
|
// Async read without callback returns a promise
|
|
(async () => {
|
|
const dir = myVfs.opendirSync('/d');
|
|
const entry = await dir.read();
|
|
assert.ok(entry);
|
|
await dir.close();
|
|
})().then(common.mustCall());
|
|
|
|
// using/explicit resource management
|
|
{
|
|
const dir = myVfs.opendirSync('/d');
|
|
dir[Symbol.dispose]();
|
|
assert.throws(() => dir.readSync(), { code: 'ERR_DIR_CLOSED' });
|
|
}
|
|
|
|
// opendir (callback)
|
|
myVfs.opendir('/d', common.mustSucceed((dir) => {
|
|
assert.strictEqual(dir.path, '/d');
|
|
dir.closeSync();
|
|
}));
|
|
|
|
// read() callback on a closed dir delivers ERR_DIR_CLOSED
|
|
{
|
|
const dir = myVfs.opendirSync('/d');
|
|
dir.closeSync();
|
|
dir.read(common.mustCall((err) => {
|
|
assert.strictEqual(err.code, 'ERR_DIR_CLOSED');
|
|
}));
|
|
// entries() iteration on a closed dir rejects with ERR_DIR_CLOSED
|
|
(async () => {
|
|
await assert.rejects(
|
|
// eslint-disable-next-line no-unused-vars
|
|
(async () => { for await (const _ of dir.entries()); })(),
|
|
{ code: 'ERR_DIR_CLOSED' });
|
|
})().then(common.mustCall());
|
|
// [Symbol.dispose] is a no-op on an already-closed dir (must not throw)
|
|
dir[Symbol.dispose]();
|
|
}
|
|
|
|
// Async dir.close() returns a promise when invoked without a callback
|
|
(async () => {
|
|
const dir = myVfs.opendirSync('/d');
|
|
await dir.close();
|
|
})().then(common.mustCall());
|
|
|
|
// opendirSync without options object
|
|
{
|
|
const dir = myVfs.opendirSync('/d');
|
|
dir.closeSync();
|
|
}
|
|
|
|
// Opendir error path (missing directory)
|
|
myVfs.opendir('/missing-dir', common.mustCall((err) => {
|
|
assert.ok(err);
|
|
}));
|