Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(node_compat): Add a write method to the FileHandle class #19385

Merged
merged 11 commits into from
Jun 8, 2023
39 changes: 35 additions & 4 deletions cli/tests/unit_node/_fs/_fs_handle_test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import * as path from "../../../../test_util/std/path/mod.ts";
import { Buffer } from "node:buffer";
import * as fs from "node:fs/promises";
import {
assert,
assertEquals,
} from "../../../../test_util/std/testing/asserts.ts";
import { Buffer } from "node:buffer";

const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testData = path.resolve(moduleDir, "testdata", "hello.txt");
const decoder = new TextDecoder();

Deno.test("readFileSuccess", async function () {
const fileHandle = await fs.open(testData);
const data = await fileHandle.readFile();

assert(data instanceof Uint8Array);
assertEquals(new TextDecoder().decode(data as Uint8Array), "hello world");
assertEquals(decoder.decode(data as Uint8Array), "hello world");

await fileHandle.close();
});
Expand All @@ -27,7 +28,7 @@ Deno.test("read", async function () {
const buf = new Buffer(byteLength);
await fileHandle.read(buf, 0, byteLength, 0);

assertEquals(new TextDecoder().decode(buf as Uint8Array), "hello world");
assertEquals(decoder.decode(buf as Uint8Array), "hello world");

await fileHandle.close();
});
Expand All @@ -54,7 +55,37 @@ Deno.test("read specify opt", async function () {
res = await fileHandle.read(opt2);

assertEquals(res.bytesRead, byteLength);
assertEquals(new TextDecoder().decode(res.buffer as Uint8Array), "hello");
assertEquals(decoder.decode(res.buffer as Uint8Array), "hello");

await fileHandle.close();
});

Deno.test("[node/fs filehandle.write] Write from Buffer", async function () {
const tempFile: string = await Deno.makeTempFile();
const fileHandle = await fs.open(tempFile, "a+");

const buffer = Buffer.from("hello world");
const res = await fileHandle.write(buffer, 0, 5, 0);

const data = Deno.readFileSync(tempFile);
await Deno.remove(tempFile);
await fileHandle.close();

assertEquals(res.bytesWritten, 5);
assertEquals(decoder.decode(data), "hello");
});

Deno.test("[node/fs filehandle.write] Write from string", async function () {
const tempFile: string = await Deno.makeTempFile();
const fileHandle = await fs.open(tempFile, "a+");

const str = "hello world";
const res = await fileHandle.write(str);

const data = Deno.readFileSync(tempFile);
await Deno.remove(tempFile);
await fileHandle.close();

assertEquals(res.bytesWritten, 11);
assertEquals(decoder.decode(data), "hello world");
});
63 changes: 61 additions & 2 deletions ext/node/polyfills/internal/fs/handle.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { EventEmitter } from "ext:deno_node/events.ts";
import { Buffer } from "ext:deno_node/buffer.ts";
import { promises, read } from "ext:deno_node/fs.ts";
import type { Buffer } from "ext:deno_node/buffer.ts";
import { promises, read, write } from "ext:deno_node/fs.ts";
import {
BinaryOptionsArgument,
FileOptionsArgument,
ReadOptions,
TextOptionsArgument,
} from "ext:deno_node/_fs/_fs_common.ts";

interface WriteResult {
bytesWritten: number;
buffer: Buffer | string;
}

interface ReadResult {
bytesRead: number;
buffer: Buffer;
Expand Down Expand Up @@ -69,6 +73,61 @@ export class FileHandle extends EventEmitter {
return promises.readFile(this, opt);
}

write(
buffer: Buffer,
offset: number,
length: number,
position: number,
): Promise<WriteResult>;
write(
str: string,
position: number,
encoding: string,
): Promise<WriteResult>;
write(
bufferOrStr: Buffer | string,
offsetOrPotition: number,
lengthOrEncoding: number | string,
position?: number,
): Promise<WriteResult> {
if (bufferOrStr instanceof Buffer) {
const buffer = bufferOrStr;
const offset = offsetOrPotition;
const length = lengthOrEncoding;

return new Promise((resolve, reject) => {
write(
this.fd,
buffer,
offset,
length,
position,
(err, bytesWritten, buffer) => {
if (err) reject(err);
else resolve({ buffer, bytesWritten });
},
);
});
} else {
const str = bufferOrStr;
const position = offsetOrPotition;
const encoding = lengthOrEncoding;

return new Promise((resolve, reject) => {
write(
this.fd,
str,
position,
encoding,
(err, bytesWritten, buffer) => {
if (err) reject(err);
else resolve({ buffer, bytesWritten });
},
);
});
}
}

close(): Promise<void> {
// Note that Deno.close is not async
return Promise.resolve(Deno.close(this.fd));
Expand Down