From 2ce01b71853996b60b8fce676090f766d1319c22 Mon Sep 17 00:00:00 2001 From: streamich Date: Sun, 25 Jun 2023 11:26:27 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20make=20memfs()=20ret?= =?UTF-8?q?urn=20a=20collection=20of=20things?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/git/index.ts | 2 +- src/__tests__/volume/readFile.test.ts | 4 +- src/__tests__/volume/writeSync.test.ts | 2 +- src/crud-to-cas/__tests__/CrudCas.test.ts | 6 +- src/crud/__tests__/matryoshka.test.ts | 12 +- src/fsa-to-crud/__tests__/FsaCrud.test.ts | 2 +- src/fsa-to-node/__tests__/FsaNodeFs.test.ts | 106 +++++++++--------- src/index.ts | 8 +- src/node-to-crud/__tests__/FsaCrud.test.ts | 2 +- .../NodeFileSystemDirectoryHandle.test.ts | 10 +- .../NodeFileSystemFileHandle.test.ts | 12 +- .../__tests__/NodeFileSystemHandle.test.ts | 2 +- .../NodeFileSystemSyncAccessHandle.test.ts | 2 +- .../NodeFileSystemWritableFileStream.test.ts | 36 +++--- src/node-to-fsa/__tests__/scenarios.test.ts | 8 +- 15 files changed, 107 insertions(+), 107 deletions(-) diff --git a/demo/git/index.ts b/demo/git/index.ts index 4dc120870..59842b592 100644 --- a/demo/git/index.ts +++ b/demo/git/index.ts @@ -4,7 +4,7 @@ import git from 'isomorphic-git'; import {memfs} from '../../src'; const main = async () => { - const fs = memfs(); + const {fs} = memfs(); fs.mkdirSync('/repo'); console.log('New folder:', (fs).__vol.toJSON()); diff --git a/src/__tests__/volume/readFile.test.ts b/src/__tests__/volume/readFile.test.ts index ec33f435b..16d5af9a0 100644 --- a/src/__tests__/volume/readFile.test.ts +++ b/src/__tests__/volume/readFile.test.ts @@ -3,13 +3,13 @@ import { memfs } from '../..'; describe('.readFile()', () => { it('can read a file', async () => { - const fs = memfs({ '/dir/test.txt': '01234567' }); + const { fs } = memfs({ '/dir/test.txt': '01234567' }); const data = await fs.promises.readFile('/dir/test.txt', { encoding: 'utf8' }); expect(data).toBe('01234567'); }); it('throws if file does not exist', async () => { - const fs = memfs({ '/dir/test.txt': '01234567' }); + const { fs } = memfs({ '/dir/test.txt': '01234567' }); const [, err] = await of(fs.promises.readFile('/dir/test-NOT-FOUND.txt', { encoding: 'utf8' })); expect(err).toBeInstanceOf(Error); expect((err).code).toBe('ENOENT'); diff --git a/src/__tests__/volume/writeSync.test.ts b/src/__tests__/volume/writeSync.test.ts index 80f9104ae..371597edf 100644 --- a/src/__tests__/volume/writeSync.test.ts +++ b/src/__tests__/volume/writeSync.test.ts @@ -19,7 +19,7 @@ describe('.writeSync(fd, buffer, offset, length, position)', () => { }); it('can write at offset', () => { - const fs = memfs({ foo: '123' }); + const { fs } = memfs({ foo: '123' }); const fd = fs.openSync('/foo', 'a+'); expect(fs.readFileSync('/foo', 'utf8')).toBe('123'); fs.writeSync(fd, 'x', 1); diff --git a/src/crud-to-cas/__tests__/CrudCas.test.ts b/src/crud-to-cas/__tests__/CrudCas.test.ts index 4c4e2750e..af5a82c6a 100644 --- a/src/crud-to-cas/__tests__/CrudCas.test.ts +++ b/src/crud-to-cas/__tests__/CrudCas.test.ts @@ -8,7 +8,7 @@ import { NodeCrud } from '../../node-to-crud/NodeCrud'; onlyOnNode20('CrudCas on FsaCrud', () => { const setup = () => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const crud = new FsaCrud(fsa); const cas = new CrudCas(crud, { hash }); @@ -19,7 +19,7 @@ onlyOnNode20('CrudCas on FsaCrud', () => { onlyOnNode20('CrudCas on NodeCrud at root', () => { const setup = () => { - const fs = memfs(); + const { fs } = memfs(); const crud = new NodeCrud({ fs: fs.promises, dir: '/' }); const cas = new CrudCas(crud, { hash }); return { fs, crud, cas, snapshot: () => (fs).__vol.toJSON() }; @@ -29,7 +29,7 @@ onlyOnNode20('CrudCas on NodeCrud at root', () => { onlyOnNode20('CrudCas on NodeCrud at in sub-folder', () => { const setup = () => { - const fs = memfs({ '/a/b/c': null }); + const { fs } = memfs({ '/a/b/c': null }); const crud = new NodeCrud({ fs: fs.promises, dir: '/a/b/c' }); const cas = new CrudCas(crud, { hash }); return { fs, crud, cas, snapshot: () => (fs).__vol.toJSON() }; diff --git a/src/crud/__tests__/matryoshka.test.ts b/src/crud/__tests__/matryoshka.test.ts index 3683d0121..00ec5034a 100644 --- a/src/crud/__tests__/matryoshka.test.ts +++ b/src/crud/__tests__/matryoshka.test.ts @@ -9,7 +9,7 @@ import { FsaCrud } from '../../fsa-to-crud'; onlyOnNode20('CRUD matryoshka', () => { describe('crud(memfs)', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const crud = new NodeCrud({ fs: fs.promises, dir: '/' }); return { crud, snapshot: () => (fs).__vol.toJSON() }; }); @@ -17,7 +17,7 @@ onlyOnNode20('CRUD matryoshka', () => { describe('crud(fsa(memfs))', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const crud = new FsaCrud(fsa); return { crud, snapshot: () => (fs).__vol.toJSON() }; @@ -26,7 +26,7 @@ onlyOnNode20('CRUD matryoshka', () => { describe('crud(fs(fsa(memfs)))', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const fs2 = new FsaNodeFs(fsa); const crud = new NodeCrud({ fs: fs2.promises, dir: '/' }); @@ -36,7 +36,7 @@ onlyOnNode20('CRUD matryoshka', () => { describe('crud(fsa(fs(fsa(memfs))))', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const fs2 = new FsaNodeFs(fsa); const fsa2 = new NodeFileSystemDirectoryHandle(fs2, '/', { mode: 'readwrite' }); @@ -47,7 +47,7 @@ onlyOnNode20('CRUD matryoshka', () => { describe('crud(fs(fsa(fs(fsa(memfs)))))', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const fs2 = new FsaNodeFs(fsa); const fsa2 = new NodeFileSystemDirectoryHandle(fs2, '/', { mode: 'readwrite' }); @@ -59,7 +59,7 @@ onlyOnNode20('CRUD matryoshka', () => { describe('crud(fsa(fs(fsa(fs(fsa(memfs))))))', () => { testCrudfs(() => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const fs2 = new FsaNodeFs(fsa); const fsa2 = new NodeFileSystemDirectoryHandle(fs2, '/', { mode: 'readwrite' }); diff --git a/src/fsa-to-crud/__tests__/FsaCrud.test.ts b/src/fsa-to-crud/__tests__/FsaCrud.test.ts index bac306c04..9eb023ac6 100644 --- a/src/fsa-to-crud/__tests__/FsaCrud.test.ts +++ b/src/fsa-to-crud/__tests__/FsaCrud.test.ts @@ -5,7 +5,7 @@ import { FsaCrud } from '../FsaCrud'; import { testCrudfs } from '../../crud/__tests__/testCrudfs'; const setup = () => { - const fs = memfs(); + const { fs } = memfs(); const fsa = new NodeFileSystemDirectoryHandle(fs, '/', { mode: 'readwrite' }); const crud = new FsaCrud(fsa); return { fs, fsa, crud, snapshot: () => (fs).__vol.toJSON() }; diff --git a/src/fsa-to-node/__tests__/FsaNodeFs.test.ts b/src/fsa-to-node/__tests__/FsaNodeFs.test.ts index 56fe6db63..0e78ec758 100644 --- a/src/fsa-to-node/__tests__/FsaNodeFs.test.ts +++ b/src/fsa-to-node/__tests__/FsaNodeFs.test.ts @@ -8,10 +8,10 @@ import { onlyOnNode20 } from '../../__tests__/util'; import { FLAG } from '../../consts/FLAG'; const setup = (json: NestedDirectoryJSON | null = null, mode: 'read' | 'readwrite' = 'readwrite') => { - const mfs = memfs({ mountpoint: json }) as IFsWithVolume; + const { fs: mfs, vol } = memfs({ mountpoint: json }); const dir = nodeToFsa(mfs, '/mountpoint', { mode, syncHandleAllowed: true }); const fs = new FsaNodeFs(dir); - return { fs, mfs, dir }; + return { fs, mfs, vol, dir }; }; onlyOnNode20('FsaNodeFs', () => { @@ -92,19 +92,19 @@ onlyOnNode20('FsaNodeFs', () => { describe('.rmdir()', () => { test('can remove an empty folder', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); await fs.promises.rmdir('/empty-folder'); - expect(mfs.__vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' }); + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' }); }); test('throws when attempts to remove non-empty folder', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); try { await fs.promises.rmdir('/folder'); throw new Error('Expected error'); } catch (error) { expect(error.code).toBe('ENOTEMPTY'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/empty-folder': null, }); @@ -112,17 +112,17 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can remove non-empty directory recursively', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rmdir('/folder', { recursive: true }); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/empty-folder': null, }); }); test('can remove starting from root folder', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rmdir('/', { recursive: true }); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint': null, }); }); @@ -130,19 +130,19 @@ onlyOnNode20('FsaNodeFs', () => { describe('.rm()', () => { test('can remove an empty folder', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); await fs.promises.rm('/empty-folder'); - expect(mfs.__vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' }); + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' }); }); test('throws when attempts to remove non-empty folder', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); try { await fs.promises.rm('/folder'); throw new Error('Expected error'); } catch (error) { expect(error.code).toBe('ENOTEMPTY'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/empty-folder': null, }); @@ -150,21 +150,21 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can remove non-empty directory recursively', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rm('/folder', { recursive: true }); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/empty-folder': null, }); }); test('throws if path does not exist', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); try { await fs.promises.rm('/lala/lulu', { recursive: true }); throw new Error('Expected error'); } catch (error) { expect(error.code).toBe('ENOENT'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/subfolder/file': 'test', '/mountpoint/empty-folder': null, }); @@ -172,23 +172,23 @@ onlyOnNode20('FsaNodeFs', () => { }); test('does not throw, if path does not exist, but "force" flag set', async () => { - const { fs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rm('/lala/lulu', { recursive: true, force: true }); }); test('can remove a file', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rm('/folder/subfolder/file'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/subfolder': null, '/mountpoint/empty-folder': null, }); }); test('can remove starting from root folder', async () => { - const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null }); await fs.promises.rm('/', { recursive: true }); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint': null, }); }); @@ -196,23 +196,23 @@ onlyOnNode20('FsaNodeFs', () => { describe('.unlink()', () => { test('can remove a file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); const res = await fs.promises.unlink('/folder/file'); expect(res).toBe(undefined); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder': null, '/mountpoint/empty-folder': null, }); }); test('cannot delete a folder', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); try { await fs.promises.unlink('/folder'); throw new Error('Expected error'); } catch (error) { expect(error.code).toBe('EISDIR'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/empty-folder': null, }); @@ -220,13 +220,13 @@ onlyOnNode20('FsaNodeFs', () => { }); test('throws when deleting non-existing file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null }); try { await fs.promises.unlink('/folder/not-a-file'); throw new Error('Expected error'); } catch (error) { expect(error.code).toBe('ENOENT'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/empty-folder': null, }); @@ -522,9 +522,9 @@ onlyOnNode20('FsaNodeFs', () => { describe('.rename()', () => { test('can rename a file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, mfs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); await fs.promises.rename('/folder/file', '/folder/file2'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file2': 'test', '/mountpoint/empty-folder': null, '/mountpoint/f.html': 'test', @@ -638,9 +638,9 @@ onlyOnNode20('FsaNodeFs', () => { describe('.copyFile()', () => { test('can copy a file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); await fs.promises.copyFile('/folder/file', '/folder/file2'); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'test', '/mountpoint/empty-folder': null, @@ -651,7 +651,7 @@ onlyOnNode20('FsaNodeFs', () => { describe('.writeFile()', () => { test('can create a new file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const res = await new Promise((resolve, reject) => { fs.writeFile('/folder/foo', 'bar', error => { if (error) reject(error); @@ -659,7 +659,7 @@ onlyOnNode20('FsaNodeFs', () => { }); }); expect(res).toBe(undefined); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/foo': 'bar', '/mountpoint/empty-folder': null, @@ -715,7 +715,7 @@ onlyOnNode20('FsaNodeFs', () => { describe('.createWriteStream()', () => { test('can use stream to write to a new file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const stream = fs.createWriteStream('/folder/file2'); stream.write(Buffer.from('A')); stream.write(Buffer.from('BC')); @@ -723,7 +723,7 @@ onlyOnNode20('FsaNodeFs', () => { stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(6); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'ABCDEF', '/mountpoint/empty-folder': null, @@ -732,7 +732,7 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can use stream to write to a new file using strings', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const stream = fs.createWriteStream('/folder/file2'); stream.write('A'); stream.write('BC'); @@ -740,7 +740,7 @@ onlyOnNode20('FsaNodeFs', () => { stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(6); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'ABCDEF', '/mountpoint/empty-folder': null, @@ -749,14 +749,14 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can use stream to overwrite existing file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const stream = fs.createWriteStream('/folder/file'); stream.write(Buffer.from('A')); stream.write(Buffer.from('BC')); stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(3); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'ABC', '/mountpoint/empty-folder': null, '/mountpoint/f.html': 'test', @@ -764,14 +764,14 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can write by file descriptor', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, mfs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const handle = await fs.promises.open('/folder/file', 'a'); const stream = fs.createWriteStream('', { fd: handle.fd, start: 1, flags: 'a' }); stream.write(Buffer.from('BC')); stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(2); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'tBCt', '/mountpoint/empty-folder': null, '/mountpoint/f.html': 'test', @@ -819,14 +819,14 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can use stream to add to existing file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const stream = fs.createWriteStream('/folder/file', { flags: 'a' }); stream.write(Buffer.from('A')); stream.write(Buffer.from('BC')); stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(3); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'ABCt', '/mountpoint/empty-folder': null, '/mountpoint/f.html': 'test', @@ -834,14 +834,14 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can use stream to add to existing file at specified offset', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const stream = fs.createWriteStream('/folder/file', { flags: 'a', start: 1 }); stream.write(Buffer.from('A')); stream.write(Buffer.from('B')); stream.end(); await new Promise(resolve => stream.once('close', resolve)); expect(stream.bytesWritten).toBe(2); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'tABt', '/mountpoint/empty-folder': null, '/mountpoint/f.html': 'test', @@ -873,12 +873,12 @@ onlyOnNode20('FsaNodeFs', () => { describe('.createReadStream()', () => { test('can pipe fs.ReadStream to fs.WriteStream', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const readStream = fs.createReadStream('/folder/file'); const writeStream = fs.createWriteStream('/folder/file2'); readStream.pipe(writeStream); await new Promise(resolve => writeStream.once('close', resolve)); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'test', '/mountpoint/empty-folder': null, @@ -908,13 +908,13 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can write to already open file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const handle = await fs.promises.open('/folder/file'); const readStream = fs.createReadStream('xyz', { fd: handle.fd }); const writeStream = fs.createWriteStream('/folder/file2'); readStream.pipe(writeStream); await new Promise(resolve => writeStream.once('close', resolve)); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'test', '/mountpoint/empty-folder': null, @@ -923,12 +923,12 @@ onlyOnNode20('FsaNodeFs', () => { }); test('can read a specified slice of a file', async () => { - const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); + const { fs, vol } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }); const readStream = fs.createReadStream('/folder/file', { start: 1, end: 2 }); const writeStream = fs.createWriteStream('/folder/file2'); readStream.pipe(writeStream); await new Promise(resolve => writeStream.once('close', resolve)); - expect(mfs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test', '/mountpoint/folder/file2': 'es', '/mountpoint/empty-folder': null, diff --git a/src/index.ts b/src/index.ts index e234a26cb..31d4bee3e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -65,10 +65,10 @@ export const fs: IFs = createFsFromVolume(vol); * @returns A `memfs` file system instance, which is a drop-in replacement for * the `fs` module. */ -export const memfs = (json: NestedDirectoryJSON = {}, cwd: string = '/'): IFs => { - const volume = Volume.fromNestedJSON(json, cwd); - const fs = createFsFromVolume(volume); - return fs; +export const memfs = (json: NestedDirectoryJSON = {}, cwd: string = '/'): { fs: IFs; vol: _Volume } => { + const vol = Volume.fromNestedJSON(json, cwd); + const fs = createFsFromVolume(vol); + return { fs, vol }; }; export type IFsWithVolume = IFs & { __vol: _Volume }; diff --git a/src/node-to-crud/__tests__/FsaCrud.test.ts b/src/node-to-crud/__tests__/FsaCrud.test.ts index e6ab8fddf..019589981 100644 --- a/src/node-to-crud/__tests__/FsaCrud.test.ts +++ b/src/node-to-crud/__tests__/FsaCrud.test.ts @@ -4,7 +4,7 @@ import { NodeCrud } from '../NodeCrud'; import { testCrudfs } from '../../crud/__tests__/testCrudfs'; const setup = () => { - const fs = memfs(); + const { fs } = memfs(); const crud = new NodeCrud({ fs: fs.promises, dir: '/', diff --git a/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts index 95f497897..d70c2de61 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts @@ -5,7 +5,7 @@ import { NodeFileSystemHandle } from '../NodeFileSystemHandle'; import { onlyOnNode20 } from '../../__tests__/util'; const setup = (json: DirectoryJSON = {}) => { - const fs = memfs(json, '/'); + const { fs } = memfs(json, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'readwrite' }); return { dir, fs }; }; @@ -160,7 +160,7 @@ onlyOnNode20('NodeFileSystemDirectoryHandle', () => { }); test('throws if not in "readwrite" mode and attempting to create a directory', async () => { - const fs = memfs({}, '/'); + const { fs } = memfs({}, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'read' }); try { await dir.getDirectoryHandle('test', { create: true }); @@ -255,7 +255,7 @@ onlyOnNode20('NodeFileSystemDirectoryHandle', () => { }); test('throws if not in "readwrite" mode and attempting to create a file', async () => { - const fs = memfs({}, '/'); + const { fs } = memfs({}, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'read' }); try { await dir.getFileHandle('test', { create: true }); @@ -339,7 +339,7 @@ onlyOnNode20('NodeFileSystemDirectoryHandle', () => { }); test('throws if not in "readwrite" mode and attempting to remove a file', async () => { - const fs = memfs({ a: 'b' }, '/'); + const { fs } = memfs({ a: 'b' }, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'read' }); try { await dir.removeEntry('a'); @@ -354,7 +354,7 @@ onlyOnNode20('NodeFileSystemDirectoryHandle', () => { }); test('throws if not in "readwrite" mode and attempting to remove a folder', async () => { - const fs = memfs({ a: null }, '/'); + const { fs } = memfs({ a: null }, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'read' }); try { await dir.removeEntry('a'); diff --git a/src/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.ts index 98d8b2077..13892ea52 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.ts @@ -3,9 +3,9 @@ import { NodeFileSystemDirectoryHandle } from '../NodeFileSystemDirectoryHandle' import { onlyOnNode20 } from '../../__tests__/util'; const setup = (json: DirectoryJSON = {}) => { - const fs = memfs(json, '/') as IFsWithVolume; + const { fs, vol } = memfs(json, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'readwrite' }); - return { dir, fs }; + return { dir, fs, vol }; }; onlyOnNode20('NodeFileSystemFileHandle', () => { @@ -27,7 +27,7 @@ onlyOnNode20('NodeFileSystemFileHandle', () => { describe('.createWritable()', () => { test('throws if not in "readwrite" mode', async () => { - const fs = memfs({ 'file.txt': 'abc' }, '/') as IFsWithVolume; + const { fs } = memfs({ 'file.txt': 'abc' }, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'read' }); const entry = await dir.getFileHandle('file.txt'); try { @@ -139,18 +139,18 @@ onlyOnNode20('NodeFileSystemFileHandle', () => { }); test('does not commit changes if .abort() is called and removes the swap file', async () => { - const { dir, fs } = setup({ + const { dir, vol } = setup({ 'file.txt': '...', }); const entry = await dir.getFileHandle('file.txt'); const writable = await entry.createWritable(); await writable.write('1'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/file.txt': '...', '/file.txt.crswap': '1', }); await writable.abort(); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/file.txt': '...', }); }); diff --git a/src/node-to-fsa/__tests__/NodeFileSystemHandle.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemHandle.test.ts index 058e41452..802e80096 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemHandle.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemHandle.test.ts @@ -3,7 +3,7 @@ import { NodeFileSystemDirectoryHandle } from '../NodeFileSystemDirectoryHandle' import { onlyOnNode20 } from '../../__tests__/util'; const setup = (json: DirectoryJSON = {}) => { - const fs = memfs(json, '/'); + const { fs } = memfs(json, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { mode: 'readwrite' }); return { dir, fs }; }; diff --git a/src/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.ts index 0b95b5884..4b2b54b49 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.ts @@ -4,7 +4,7 @@ import { NodeFileSystemSyncAccessHandle } from '../NodeFileSystemSyncAccessHandl import { onlyOnNode20 } from '../../__tests__/util'; const setup = (json: DirectoryJSON = {}) => { - const fs = memfs(json, '/'); + const { fs } = memfs(json, '/'); const dir = new NodeFileSystemDirectoryHandle(fs as any, '/', { syncHandleAllowed: true, mode: 'readwrite' }); return { dir, fs }; }; diff --git a/src/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.ts index 338ffcbc4..c65defad4 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.ts @@ -4,49 +4,49 @@ import { createSwapFile } from '../NodeFileSystemWritableFileStream'; describe('createSwapFile()', () => { test('can create a swap file', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/file.txt': 'Hello, world!', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/file.txt', false); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/file.txt.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/file.txt': 'Hello, world!', '/file.txt.crswap': '', }); }); test('can create a swap file at subfolder', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/foo/file.txt': 'Hello, world!', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/foo/file.txt', false); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/foo/file.txt.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': '', }); }); test('can create a swap file when the default swap file name is in use', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/foo/file.txt', false); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/foo/file.txt.1.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', '/foo/file.txt.1.crswap': '', @@ -54,18 +54,18 @@ describe('createSwapFile()', () => { }); test('can create a swap file when the first two names are already taken', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', '/foo/file.txt.1.crswap': 'blah', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/foo/file.txt', false); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/foo/file.txt.2.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', '/foo/file.txt.1.crswap': 'blah', @@ -74,7 +74,7 @@ describe('createSwapFile()', () => { }); test('can create a swap file when the first three names are already taken', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', @@ -82,11 +82,11 @@ describe('createSwapFile()', () => { '/foo/file.txt.2.crswap': 'brawo', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/foo/file.txt', false); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/foo/file.txt.3.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', '/foo/file.txt.1.crswap': 'blah', @@ -96,7 +96,7 @@ describe('createSwapFile()', () => { }); test('can copy existing data into the swap file', async () => { - const fs = memfs( + const { fs, vol } = memfs( { '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', @@ -104,11 +104,11 @@ describe('createSwapFile()', () => { '/foo/file.txt.2.crswap': 'brawo', }, '/', - ) as IFsWithVolume; + ); const [handle, path] = await createSwapFile(fs, '/foo/file.txt', true); expect(handle).toBeInstanceOf(FileHandle); expect(path).toBe('/foo/file.txt.3.crswap'); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/foo/file.txt': 'Hello, world!', '/foo/file.txt.crswap': 'lala', '/foo/file.txt.1.crswap': 'blah', diff --git a/src/node-to-fsa/__tests__/scenarios.test.ts b/src/node-to-fsa/__tests__/scenarios.test.ts index 54afb6142..8aaadd1b4 100644 --- a/src/node-to-fsa/__tests__/scenarios.test.ts +++ b/src/node-to-fsa/__tests__/scenarios.test.ts @@ -1,15 +1,15 @@ import { nodeToFsa } from '..'; -import { IFsWithVolume, memfs } from '../..'; +import { memfs } from '../..'; import { onlyOnNode20 } from '../../__tests__/util'; onlyOnNode20('scenarios', () => { test('can init FSA from an arbitrary FS folder and execute operations', async () => { - const fs = memfs({ + const { fs, vol } = memfs({ '/tmp': null, '/etc': null, '/bin': null, '/Users/kasper/Documents/shopping-list.txt': 'Milk, Eggs, Bread', - }) as IFsWithVolume; + }); const dir = nodeToFsa(fs, '/Users/kasper/Documents', { mode: 'readwrite' }); const shoppingListFile = await dir.getFileHandle('shopping-list.txt'); const shoppingList = await shoppingListFile.getFile(); @@ -24,7 +24,7 @@ onlyOnNode20('scenarios', () => { await logsWritable.write('timestamp,level,message\n'); await logsWritable.write({ type: 'write', data: '2021-01-01T00:00:00Z,INFO,Hello World\n' }); await logsWritable.close(); - expect(fs.__vol.toJSON()).toStrictEqual({ + expect(vol.toJSON()).toStrictEqual({ '/tmp': null, '/etc': null, '/bin': null,