Skip to content

Commit c413df5

Browse files
authoredDec 9, 2024
feat: implement createReadStream and createWriteStream on FileHandle (#1076)
* feat: implement `createReadStream` and `createWriteStream` on `FileHandle` Closes #1063 * test for FileHandle#create{Read,Write}Stream
1 parent cf16b76 commit c413df5

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed
 

‎src/__tests__/promises.test.ts

+34
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { promisify } from 'util';
12
import { Volume } from '../volume';
23
import { Readable } from 'stream';
34

@@ -82,6 +83,39 @@ describe('Promises API', () => {
8283
});
8384
});
8485
// close(): covered by all other tests
86+
it('supports createReadStream()', done => {
87+
const vol = Volume.fromJSON({
88+
'/test.txt': 'Hello',
89+
});
90+
vol.promises
91+
.open('/test.txt', 'r')
92+
.then(fh => {
93+
const readStream = fh.createReadStream({});
94+
readStream.setEncoding('utf8');
95+
let readData = '';
96+
readStream.on('readable', () => {
97+
const chunk = readStream.read();
98+
if (chunk != null) readData += chunk;
99+
});
100+
readStream.on('end', () => {
101+
expect(readData).toEqual('Hello');
102+
done();
103+
});
104+
})
105+
.catch(err => {
106+
expect(err).toBeNull();
107+
});
108+
});
109+
it('supports createWriteStream()', async () => {
110+
const vol = new Volume();
111+
const fh = await vol.promises.open('/test.txt', 'wx', 0o600);
112+
const writeStream = fh.createWriteStream({});
113+
await promisify(writeStream.write.bind(writeStream))(Buffer.from('Hello'));
114+
await promisify(writeStream.close.bind(writeStream))();
115+
expect(vol.toJSON()).toEqual({
116+
'/test.txt': 'Hello',
117+
});
118+
});
85119
describe('datasync()', () => {
86120
const vol = new Volume();
87121
const { promises } = vol;

‎src/node/FileHandle.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { promisify } from './util';
22
import type * as opts from './types/options';
3-
import type { IFileHandle, IStats, TData, TDataOut, TMode, TTime } from './types/misc';
3+
import type { IFileHandle, IReadStream, IWriteStream, IStats, TData, TDataOut, TMode, TTime } from './types/misc';
44
import type { FsCallbackApi } from './types';
55

66
export class FileHandle implements IFileHandle {
@@ -33,6 +33,14 @@ export class FileHandle implements IFileHandle {
3333
return promisify(this.fs, 'fdatasync')(this.fd);
3434
}
3535

36+
createReadStream(options: opts.IFileHandleReadStreamOptions): IReadStream {
37+
return this.fs.createReadStream('', { ...options, fd: this });
38+
}
39+
40+
createWriteStream(options: opts.IFileHandleWriteStreamOptions): IWriteStream {
41+
return this.fs.createWriteStream('', { ...options, fd: this });
42+
}
43+
3644
readableWebStream(options?: opts.IReadableWebStreamOptions): ReadableStream {
3745
return new ReadableStream({
3846
pull: async controller => {

‎src/node/types/misc.ts

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type { EventEmitter } from 'events';
44
import type { TSetTimeout } from '../../setTimeoutUnref';
55
import type {
66
IAppendFileOptions,
7+
IFileHandleReadStreamOptions,
8+
IFileHandleWriteStreamOptions,
79
IReadableWebStreamOptions,
810
IReadFileOptions,
911
IStatOptions,
@@ -138,6 +140,8 @@ export interface IFileHandle {
138140
chmod(mode: TMode): Promise<void>;
139141
chown(uid: number, gid: number): Promise<void>;
140142
close(): Promise<void>;
143+
createReadStream(options: IFileHandleReadStreamOptions): IReadStream;
144+
createWriteStream(options: IFileHandleWriteStreamOptions): IWriteStream;
141145
datasync(): Promise<void>;
142146
readableWebStream(options?: IReadableWebStreamOptions): ReadableStream;
143147
read(buffer: Buffer | Uint8Array, offset: number, length: number, position: number): Promise<TFileHandleReadResult>;

‎src/node/types/options.ts

+20
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ export interface IReadableWebStreamOptions {
3636
type?: 'bytes' | undefined;
3737
}
3838

39+
export interface IFileHandleReadStreamOptions {
40+
encoding?: BufferEncoding;
41+
autoClose?: boolean;
42+
emitClose?: boolean;
43+
start?: number | undefined;
44+
end?: number;
45+
highWaterMark?: number;
46+
flush?: boolean;
47+
signal?: AbortSignal | undefined;
48+
}
49+
50+
export interface IFileHandleWriteStreamOptions {
51+
encoding?: BufferEncoding;
52+
autoClose?: boolean;
53+
emitClose?: boolean;
54+
start?: number;
55+
highWaterMark?: number;
56+
flush?: boolean;
57+
}
58+
3959
export interface IReaddirOptions extends IOptions {
4060
recursive?: boolean;
4161
withFileTypes?: boolean;

0 commit comments

Comments
 (0)