Skip to content

Commit

Permalink
feat: 🎸 improve writing at offset logic
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 14, 2023
1 parent b363689 commit 392932a
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 9 deletions.
8 changes: 6 additions & 2 deletions src/node-to-fsa/NodeFileSystemFileHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ export class NodeFileSystemFileHandle extends NodeFileSystemHandle {
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle/createWritable
*/
public async createWritable(
{ keepExistingData = false }: { keepExistingData?: boolean } = { keepExistingData: false },
{ keepExistingData = false }: CreateWritableOptions = { keepExistingData: false },
): Promise<NodeFileSystemWritableFileStream> {
return new NodeFileSystemWritableFileStream(this.fs, this.__path);
return new NodeFileSystemWritableFileStream(this.fs, this.__path, keepExistingData);
}
}

export interface CreateWritableOptions {
keepExistingData?: boolean;
}
19 changes: 13 additions & 6 deletions src/node-to-fsa/NodeFileSystemWritableFileStream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { IFileHandle } from '../promises';
import type { NodeFsaFs } from './types';

interface Ref {
handle: IFileHandle | undefined;
offset: number;
}

/**
* Is a WritableStream object with additional convenience methods, which
* operates on a single file on disk. The interface is accessed through the
Expand All @@ -9,21 +14,22 @@ import type { NodeFsaFs } from './types';
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemWritableFileStream
*/
export class NodeFileSystemWritableFileStream extends WritableStream {
protected handle: IFileHandle | undefined = undefined;
protected readonly ref: Ref;

constructor(protected readonly fs: NodeFsaFs, protected readonly path: string) {
const ref: { handle: IFileHandle | undefined } = { handle: undefined };
constructor(protected readonly fs: NodeFsaFs, protected readonly path: string, keepExistingData: boolean) {
const ref: Ref = { handle: undefined, offset: 0 };
super({
async start() {
ref.handle = await fs.promises.open(path, 'w');
ref.handle = await fs.promises.open(path, keepExistingData ? 'a+' : 'w');
},
async write(chunk: Data) {
const handle = ref.handle;
if (!handle) throw new Error('Invalid state');
const buffer = Buffer.from(
typeof chunk === 'string' ? chunk : chunk instanceof Blob ? await chunk.arrayBuffer() : chunk,
);
await handle.write(buffer);
const { bytesWritten } = await handle.write(buffer, 0, buffer.length, ref.offset);
ref.offset += bytesWritten;
},
async close() {
if (ref.handle) await ref.handle.close();
Expand All @@ -32,6 +38,7 @@ export class NodeFileSystemWritableFileStream extends WritableStream {
if (ref.handle) await ref.handle.close();
},
});
this.ref = ref;
}

/**
Expand All @@ -40,7 +47,7 @@ export class NodeFileSystemWritableFileStream extends WritableStream {
* (beginning) of the file.
*/
public async seek(position: number): Promise<void> {
throw new Error('Not implemented');
this.ref.offset = position;
}

/**
Expand Down
15 changes: 14 additions & 1 deletion src/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ maybe('NodeFileSystemFileHandle', () => {

describe('.createWritable()', () => {
describe('.write(chunk)', () => {
test('can write to file', async () => {
test('overwrites the file when write is being executed', async () => {
const { dir, fs } = setup({
'file.txt': 'Hello, world!',
});
Expand All @@ -37,6 +37,19 @@ maybe('NodeFileSystemFileHandle', () => {
await writable.close();
expect(fs.readFileSync('/file.txt', 'utf8')).toBe('...');
});

test('can seek and then write', async () => {
const { dir, fs } = setup({
'file.txt': '...',
});
const entry = await dir.getFileHandle('file.txt');
const writable = await entry.createWritable({keepExistingData: true});
writable.seek(1);
await writable.write('1');
await writable.write('2');
await writable.close();
expect(fs.readFileSync('/file.txt', 'utf8')).toBe('.12');
});
});
});
});

0 comments on commit 392932a

Please sign in to comment.