summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcos Casagrande <marcoscvp90@gmail.com>2020-05-05 00:59:37 +0200
committerGitHub <noreply@github.com>2020-05-04 18:59:37 -0400
commitf0aea98c85e18b297593ed6483b620945483fa37 (patch)
tree4176b47a2162e2713169a1d7858fdb6aec3a4ed5
parent5f67a202ff59f25ea183c261f664a6db06407e17 (diff)
feat(std/node): fs.writefile / fs.promises.writeFile (#5054)
-rw-r--r--std/node/_fs/_fs_appendFile.ts92
-rw-r--r--std/node/_fs/_fs_common.ts124
-rw-r--r--std/node/_fs/_fs_copy_test.ts2
-rw-r--r--std/node/_fs/_fs_readFile.ts39
-rw-r--r--std/node/_fs/_fs_writeFile.ts65
-rw-r--r--std/node/_fs/_fs_writeFile_test.ts180
-rw-r--r--std/node/_fs/promises/_fs_writeFile.ts17
-rw-r--r--std/node/_fs/promises/_fs_writeFile_test.ts119
-rw-r--r--std/node/_fs/promises/mod.ts1
-rwxr-xr-xstd/node/fs.ts4
10 files changed, 522 insertions, 121 deletions
diff --git a/std/node/_fs/_fs_appendFile.ts b/std/node/_fs/_fs_appendFile.ts
index b116589a0..c0f347dbf 100644
--- a/std/node/_fs/_fs_appendFile.ts
+++ b/std/node/_fs/_fs_appendFile.ts
@@ -1,5 +1,10 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-import { FileOptions, isFileOptions, CallbackWithError } from "./_fs_common.ts";
+import {
+ WriteFileOptions,
+ isFileOptions,
+ CallbackWithError,
+ getOpenOptions,
+} from "./_fs_common.ts";
import { notImplemented } from "../_utils.ts";
import { fromFileUrl } from "../path.ts";
@@ -10,13 +15,13 @@ import { fromFileUrl } from "../path.ts";
export function appendFile(
pathOrRid: string | number | URL,
data: string,
- optionsOrCallback: string | FileOptions | CallbackWithError,
+ optionsOrCallback: string | WriteFileOptions | CallbackWithError,
callback?: CallbackWithError
): void {
pathOrRid = pathOrRid instanceof URL ? fromFileUrl(pathOrRid) : pathOrRid;
const callbackFn: CallbackWithError | undefined =
optionsOrCallback instanceof Function ? optionsOrCallback : callback;
- const options: string | FileOptions | undefined =
+ const options: string | WriteFileOptions | undefined =
optionsOrCallback instanceof Function ? undefined : optionsOrCallback;
if (!callbackFn) {
throw new Error("No callback function supplied");
@@ -74,7 +79,7 @@ function closeRidIfNecessary(isPathString: boolean, rid: number): void {
export function appendFileSync(
pathOrRid: string | number | URL,
data: string,
- options?: string | FileOptions
+ options?: string | WriteFileOptions
): void {
let rid = -1;
@@ -110,7 +115,7 @@ export function appendFileSync(
}
function validateEncoding(
- encodingOption: string | FileOptions | undefined
+ encodingOption: string | WriteFileOptions | undefined
): void {
if (!encodingOption) return;
@@ -122,80 +127,3 @@ function validateEncoding(
throw new Error("Only 'utf8' encoding is currently supported");
}
}
-
-function getOpenOptions(flag: string | undefined): Deno.OpenOptions {
- if (!flag) {
- return { create: true, append: true };
- }
-
- let openOptions: Deno.OpenOptions;
- switch (flag) {
- case "a": {
- // 'a': Open file for appending. The file is created if it does not exist.
- openOptions = { create: true, append: true };
- break;
- }
- case "ax": {
- // 'ax': Like 'a' but fails if the path exists.
- openOptions = { createNew: true, write: true, append: true };
- break;
- }
- case "a+": {
- // 'a+': Open file for reading and appending. The file is created if it does not exist.
- openOptions = { read: true, create: true, append: true };
- break;
- }
- case "ax+": {
- // 'ax+': Like 'a+' but fails if the path exists.
- openOptions = { read: true, createNew: true, append: true };
- break;
- }
- case "r": {
- // 'r': Open file for reading. An exception occurs if the file does not exist.
- openOptions = { read: true };
- break;
- }
- case "r+": {
- // 'r+': Open file for reading and writing. An exception occurs if the file does not exist.
- openOptions = { read: true, write: true };
- break;
- }
- case "w": {
- // 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
- openOptions = { create: true, write: true, truncate: true };
- break;
- }
- case "wx": {
- // 'wx': Like 'w' but fails if the path exists.
- openOptions = { createNew: true, write: true };
- break;
- }
- case "w+": {
- // 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
- openOptions = { create: true, write: true, truncate: true, read: true };
- break;
- }
- case "wx+": {
- // 'wx+': Like 'w+' but fails if the path exists.
- openOptions = { createNew: true, write: true, read: true };
- break;
- }
- case "as": {
- // 'as': Open file for appending in synchronous mode. The file is created if it does not exist.
- openOptions = { create: true, append: true };
- }
- case "as+": {
- // 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist.
- openOptions = { create: true, read: true, append: true };
- }
- case "rs+": {
- // 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.
- openOptions = { create: true, read: true, write: true };
- }
- default: {
- throw new Error(`Unrecognized file system flag: ${flag}`);
- }
- }
-
- return openOptions;
-}
diff --git a/std/node/_fs/_fs_common.ts b/std/node/_fs/_fs_common.ts
index ebdd28d64..1f00bc481 100644
--- a/std/node/_fs/_fs_common.ts
+++ b/std/node/_fs/_fs_common.ts
@@ -1,21 +1,137 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-export type CallbackWithError = (err?: Error) => void;
+import { notImplemented } from "../_utils.ts";
+
+export type CallbackWithError = (err?: Error | null) => void;
export interface FileOptions {
encoding?: string;
- mode?: number;
flag?: string;
}
+export interface WriteFileOptions extends FileOptions {
+ mode?: number;
+}
+
export function isFileOptions(
- fileOptions: string | FileOptions | undefined
+ fileOptions: string | WriteFileOptions | undefined
): fileOptions is FileOptions {
if (!fileOptions) return false;
return (
(fileOptions as FileOptions).encoding != undefined ||
(fileOptions as FileOptions).flag != undefined ||
- (fileOptions as FileOptions).mode != undefined
+ (fileOptions as WriteFileOptions).mode != undefined
);
}
+
+export function getEncoding(
+ optOrCallback?: FileOptions | WriteFileOptions | Function | string
+): string | null {
+ if (!optOrCallback || typeof optOrCallback === "function") {
+ return null;
+ }
+
+ const encoding =
+ typeof optOrCallback === "string" ? optOrCallback : optOrCallback.encoding;
+ if (!encoding) return null;
+ if (encoding === "utf8" || encoding === "utf-8") {
+ return "utf8";
+ }
+ if (encoding === "buffer") {
+ return "buffer";
+ }
+
+ const notImplementedEncodings = [
+ "utf16le",
+ "latin1",
+ "base64",
+ "hex",
+ "ascii",
+ "binary",
+ "ucs2",
+ ];
+
+ if (notImplementedEncodings.includes(encoding)) {
+ notImplemented(`"${encoding}" encoding`);
+ }
+
+ throw new Error(`The value "${encoding}" is invalid for option "encoding"`);
+}
+
+export function getOpenOptions(flag: string | undefined): Deno.OpenOptions {
+ if (!flag) {
+ return { create: true, append: true };
+ }
+
+ let openOptions: Deno.OpenOptions;
+ switch (flag) {
+ case "a": {
+ // 'a': Open file for appending. The file is created if it does not exist.
+ openOptions = { create: true, append: true };
+ break;
+ }
+ case "ax": {
+ // 'ax': Like 'a' but fails if the path exists.
+ openOptions = { createNew: true, write: true, append: true };
+ break;
+ }
+ case "a+": {
+ // 'a+': Open file for reading and appending. The file is created if it does not exist.
+ openOptions = { read: true, create: true, append: true };
+ break;
+ }
+ case "ax+": {
+ // 'ax+': Like 'a+' but fails if the path exists.
+ openOptions = { read: true, createNew: true, append: true };
+ break;
+ }
+ case "r": {
+ // 'r': Open file for reading. An exception occurs if the file does not exist.
+ openOptions = { read: true };
+ break;
+ }
+ case "r+": {
+ // 'r+': Open file for reading and writing. An exception occurs if the file does not exist.
+ openOptions = { read: true, write: true };
+ break;
+ }
+ case "w": {
+ // 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
+ openOptions = { create: true, write: true, truncate: true };
+ break;
+ }
+ case "wx": {
+ // 'wx': Like 'w' but fails if the path exists.
+ openOptions = { createNew: true, write: true };
+ break;
+ }
+ case "w+": {
+ // 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
+ openOptions = { create: true, write: true, truncate: true, read: true };
+ break;
+ }
+ case "wx+": {
+ // 'wx+': Like 'w+' but fails if the path exists.
+ openOptions = { createNew: true, write: true, read: true };
+ break;
+ }
+ case "as": {
+ // 'as': Open file for appending in synchronous mode. The file is created if it does not exist.
+ openOptions = { create: true, append: true };
+ }
+ case "as+": {
+ // 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist.
+ openOptions = { create: true, read: true, append: true };
+ }
+ case "rs+": {
+ // 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.
+ openOptions = { create: true, read: true, write: true };
+ }
+ default: {
+ throw new Error(`Unrecognized file system flag: ${flag}`);
+ }
+ }
+
+ return openOptions;
+}
diff --git a/std/node/_fs/_fs_copy_test.ts b/std/node/_fs/_fs_copy_test.ts
index 45e7e9372..9a27f7a83 100644
--- a/std/node/_fs/_fs_copy_test.ts
+++ b/std/node/_fs/_fs_copy_test.ts
@@ -12,7 +12,7 @@ test({
fn: async () => {
const srouceFile = Deno.makeTempFileSync();
const err = await new Promise((resolve) => {
- copyFile(srouceFile, destFile, (err: Error | undefined) => resolve(err));
+ copyFile(srouceFile, destFile, (err?: Error | null) => resolve(err));
});
assert(!err);
assert(existsSync(destFile));
diff --git a/std/node/_fs/_fs_readFile.ts b/std/node/_fs/_fs_readFile.ts
index 8d3c96db0..6021c84e0 100644
--- a/std/node/_fs/_fs_readFile.ts
+++ b/std/node/_fs/_fs_readFile.ts
@@ -1,10 +1,8 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-import {
- notImplemented,
- intoCallbackAPIWithIntercept,
- MaybeEmpty,
-} from "../_utils.ts";
+import { intoCallbackAPIWithIntercept, MaybeEmpty } from "../_utils.ts";
+
+import { getEncoding, FileOptions } from "./_fs_common.ts";
import { fromFileUrl } from "../path.ts";
const { readFile: denoReadFile, readFileSync: denoReadFileSync } = Deno;
@@ -14,33 +12,6 @@ type ReadFileCallback = (
data: MaybeEmpty<string | Uint8Array>
) => void;
-interface ReadFileOptions {
- encoding?: string | null;
- flag?: string;
-}
-
-function getEncoding(
- optOrCallback?: ReadFileOptions | ReadFileCallback
-): string | null {
- if (!optOrCallback || typeof optOrCallback === "function") {
- return null;
- } else {
- if (optOrCallback.encoding) {
- if (
- optOrCallback.encoding === "utf8" ||
- optOrCallback.encoding === "utf-8"
- ) {
- return "utf8";
- } else if (optOrCallback.encoding === "buffer") {
- return "buffer";
- } else {
- notImplemented();
- }
- }
- return null;
- }
-}
-
function maybeDecode(
data: Uint8Array,
encoding: string | null
@@ -53,7 +24,7 @@ function maybeDecode(
export function readFile(
path: string | URL,
- optOrCallback: ReadFileCallback | ReadFileOptions,
+ optOrCallback: ReadFileCallback | FileOptions,
callback?: ReadFileCallback
): void {
path = path instanceof URL ? fromFileUrl(path) : path;
@@ -76,7 +47,7 @@ export function readFile(
export function readFileSync(
path: string | URL,
- opt?: ReadFileOptions
+ opt?: FileOptions
): string | Uint8Array {
path = path instanceof URL ? fromFileUrl(path) : path;
return maybeDecode(denoReadFileSync(path), getEncoding(opt));
diff --git a/std/node/_fs/_fs_writeFile.ts b/std/node/_fs/_fs_writeFile.ts
new file mode 100644
index 000000000..c9f7fe125
--- /dev/null
+++ b/std/node/_fs/_fs_writeFile.ts
@@ -0,0 +1,65 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+import { notImplemented } from "../_utils.ts";
+
+import {
+ WriteFileOptions,
+ CallbackWithError,
+ isFileOptions,
+ getEncoding,
+ getOpenOptions,
+} from "./_fs_common.ts";
+
+export function writeFile(
+ pathOrRid: string | number,
+ data: string | Uint8Array,
+ optOrCallback: string | CallbackWithError | WriteFileOptions | undefined,
+ callback?: CallbackWithError
+): void {
+ const callbackFn: CallbackWithError | undefined =
+ optOrCallback instanceof Function ? optOrCallback : callback;
+ const options: string | WriteFileOptions | undefined =
+ optOrCallback instanceof Function ? undefined : optOrCallback;
+
+ if (!callbackFn) {
+ throw new TypeError("Callback must be a function.");
+ }
+
+ const flag: string | undefined = isFileOptions(options)
+ ? options.flag
+ : undefined;
+
+ const mode: number | undefined = isFileOptions(options)
+ ? options.mode
+ : undefined;
+
+ const encoding = getEncoding(options) || "utf8";
+ const openOptions = getOpenOptions(flag || "w");
+
+ if (typeof data === "string" && encoding === "utf8")
+ data = new TextEncoder().encode(data) as Uint8Array;
+
+ const isRid = typeof pathOrRid === "number";
+ let file;
+
+ let error: Error | null = null;
+ (async (): Promise<void> => {
+ try {
+ file = isRid
+ ? new Deno.File(pathOrRid as number)
+ : await Deno.open(pathOrRid as string, openOptions);
+
+ if (!isRid && mode) {
+ if (Deno.build.os === "windows") notImplemented(`"mode" on Windows`);
+ await Deno.chmod(pathOrRid as string, mode);
+ }
+
+ await Deno.writeAll(file, data as Uint8Array);
+ } catch (e) {
+ error = e;
+ } finally {
+ // Make sure to close resource
+ if (!isRid && file) file.close();
+ callbackFn(error);
+ }
+ })();
+}
diff --git a/std/node/_fs/_fs_writeFile_test.ts b/std/node/_fs/_fs_writeFile_test.ts
new file mode 100644
index 000000000..9b40a1fff
--- /dev/null
+++ b/std/node/_fs/_fs_writeFile_test.ts
@@ -0,0 +1,180 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+const { test } = Deno;
+
+import {
+ assert,
+ assertEquals,
+ assertNotEquals,
+ assertThrows,
+ assertThrowsAsync,
+} from "../../testing/asserts.ts";
+import { writeFile } from "./_fs_writeFile.ts";
+
+const decoder = new TextDecoder("utf-8");
+
+test("Invalid encoding results in error()", function fn() {
+ assertThrows(
+ () => {
+ writeFile("some/path", "some data", "utf8");
+ },
+ TypeError,
+ "Callback must be a function."
+ );
+});
+
+test("Invalid encoding results in error()", function testEncodingErrors() {
+ assertThrows(
+ () => {
+ writeFile("some/path", "some data", "made-up-encoding", () => {});
+ },
+ Error,
+ `The value "made-up-encoding" is invalid for option "encoding"`
+ );
+ assertThrows(
+ () => {
+ writeFile(
+ "some/path",
+ "some data",
+ {
+ encoding: "made-up-encoding",
+ },
+ () => {}
+ );
+ },
+ Error,
+ `The value "made-up-encoding" is invalid for option "encoding"`
+ );
+});
+
+test("Unsupported encoding results in error()", function testUnsupportedEncoding() {
+ assertThrows(
+ () => {
+ writeFile("some/path", "some data", "hex", () => {});
+ },
+ Error,
+ `Not implemented: "hex" encoding`
+ );
+ assertThrows(
+ () => {
+ writeFile(
+ "some/path",
+ "some data",
+ {
+ encoding: "base64",
+ },
+ () => {}
+ );
+ },
+ Error,
+ `Not implemented: "base64" encoding`
+ );
+});
+
+test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
+ const tempFile: string = await Deno.makeTempFile();
+ const file: Deno.File = await Deno.open(tempFile, {
+ create: true,
+ write: true,
+ read: true,
+ });
+
+ await new Promise((resolve, reject) => {
+ writeFile(file.rid, "hello world", (err) => {
+ if (err) return reject(err);
+ resolve();
+ });
+ });
+ Deno.close(file.rid);
+
+ const data = await Deno.readFile(tempFile);
+ await Deno.remove(tempFile);
+ assertEquals(decoder.decode(data), "hello world");
+});
+
+test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
+ const tempFile: string = await Deno.makeTempFile();
+ const file: Deno.File = await Deno.open(tempFile, {
+ create: true,
+ write: true,
+ read: true,
+ });
+
+ await new Promise((resolve, reject) => {
+ writeFile(file.rid, "hello world", (err) => {
+ if (err) return reject(err);
+ resolve();
+ });
+ });
+ Deno.close(file.rid);
+
+ const data = await Deno.readFile(tempFile);
+ await Deno.remove(tempFile);
+ assertEquals(decoder.decode(data), "hello world");
+});
+
+test("Data is written to correct file", async function testCorrectWriteUsingPath() {
+ const res = await new Promise((resolve) => {
+ writeFile("_fs_writeFile_test_file.txt", "hello world", resolve);
+ });
+
+ const data = await Deno.readFile("_fs_writeFile_test_file.txt");
+ await Deno.remove("_fs_writeFile_test_file.txt");
+ assertEquals(res, null);
+ assertEquals(decoder.decode(data), "hello world");
+});
+
+test("Mode is correctly set", async function testCorrectFileMode() {
+ if (Deno.build.os === "windows") return;
+ const filename = "_fs_writeFile_test_file.txt";
+
+ const res = await new Promise((resolve) => {
+ writeFile(filename, "hello world", { mode: 0o777 }, resolve);
+ });
+
+ const fileInfo = await Deno.stat(filename);
+ await Deno.remove(filename);
+ assertEquals(res, null);
+ assert(fileInfo && fileInfo.mode);
+ assertEquals(fileInfo.mode & 0o777, 0o777);
+});
+
+test("Mode is not set when rid is passed", async function testCorrectFileModeRid() {
+ if (Deno.build.os === "windows") return;
+
+ const filename: string = await Deno.makeTempFile();
+ const file: Deno.File = await Deno.open(filename, {
+ create: true,
+ write: true,
+ read: true,
+ });
+
+ await new Promise((resolve, reject) => {
+ writeFile(file.rid, "hello world", { mode: 0o777 }, (err) => {
+ if (err) return reject(err);
+ resolve();
+ });
+ });
+ Deno.close(file.rid);
+
+ const fileInfo = await Deno.stat(filename);
+ await Deno.remove(filename);
+ assert(fileInfo.mode);
+ assertNotEquals(fileInfo.mode & 0o777, 0o777);
+});
+
+test("Mode is not implemented on windows", function testModeNotImplementedWindows(): void {
+ if (Deno.build.os !== "windows") return;
+
+ assertThrowsAsync(
+ () => {
+ return new Promise((resolve, reject) => {
+ writeFile("fail.txt", "some data", { mode: 0o777 }, (err) => {
+ if (err) return reject(err);
+ resolve();
+ });
+ });
+ },
+ Error,
+ `Not implemented: "mode" on Windows`
+ );
+});
diff --git a/std/node/_fs/promises/_fs_writeFile.ts b/std/node/_fs/promises/_fs_writeFile.ts
new file mode 100644
index 000000000..a8f9586a2
--- /dev/null
+++ b/std/node/_fs/promises/_fs_writeFile.ts
@@ -0,0 +1,17 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+import { WriteFileOptions } from "../_fs_common.ts";
+
+import { writeFile as writeFileCallback } from "../_fs_writeFile.ts";
+
+export function writeFile(
+ pathOrRid: string | number,
+ data: string | Uint8Array,
+ options?: string | WriteFileOptions
+): Promise<void> {
+ return new Promise((resolve, reject) => {
+ writeFileCallback(pathOrRid, data, options, (err?: Error | null) => {
+ if (err) return reject(err);
+ resolve();
+ });
+ });
+}
diff --git a/std/node/_fs/promises/_fs_writeFile_test.ts b/std/node/_fs/promises/_fs_writeFile_test.ts
new file mode 100644
index 000000000..c67a7947a
--- /dev/null
+++ b/std/node/_fs/promises/_fs_writeFile_test.ts
@@ -0,0 +1,119 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+const { test } = Deno;
+
+import {
+ assert,
+ assertEquals,
+ assertNotEquals,
+ assertThrowsAsync,
+} from "../../../testing/asserts.ts";
+import { writeFile } from "./_fs_writeFile.ts";
+
+const decoder = new TextDecoder("utf-8");
+
+test("Invalid encoding results in error()", function testEncodingErrors() {
+ assertThrowsAsync(
+ async () => {
+ await writeFile("some/path", "some data", "made-up-encoding");
+ },
+ Error,
+ `The value "made-up-encoding" is invalid for option "encoding"`
+ );
+ assertThrowsAsync(
+ async () => {
+ await writeFile("some/path", "some data", {
+ encoding: "made-up-encoding",
+ });
+ },
+ Error,
+ `The value "made-up-encoding" is invalid for option "encoding"`
+ );
+});
+
+test("Unsupported encoding results in error()", function testUnsupportedEncoding() {
+ assertThrowsAsync(
+ async () => {
+ await writeFile("some/path", "some data", "hex");
+ },
+ Error,
+ `Not implemented: "hex" encoding`
+ );
+ assertThrowsAsync(
+ async () => {
+ await writeFile("some/path", "some data", {
+ encoding: "base64",
+ });
+ },
+ Error,
+ `Not implemented: "base64" encoding`
+ );
+});
+
+test("Data is written to correct rid", async function testCorrectWriteUsingRid() {
+ const tempFile: string = await Deno.makeTempFile();
+ const file: Deno.File = await Deno.open(tempFile, {
+ create: true,
+ write: true,
+ read: true,
+ });
+
+ await writeFile(file.rid, "hello world");
+ Deno.close(file.rid);
+
+ const data = await Deno.readFile(tempFile);
+ await Deno.remove(tempFile);
+ assertEquals(decoder.decode(data), "hello world");
+});
+
+test("Data is written to correct file", async function testCorrectWriteUsingPath() {
+ const openResourcesBeforeWrite: Deno.ResourceMap = Deno.resources();
+
+ await writeFile("_fs_writeFile_test_file.txt", "hello world");
+
+ assertEquals(Deno.resources(), openResourcesBeforeWrite);
+ const data = await Deno.readFile("_fs_writeFile_test_file.txt");
+ await Deno.remove("_fs_writeFile_test_file.txt");
+ assertEquals(decoder.decode(data), "hello world");
+});
+
+test("Mode is correctly set", async function testCorrectFileMode() {
+ if (Deno.build.os === "windows") return;
+ const filename = "_fs_writeFile_test_file.txt";
+ await writeFile(filename, "hello world", { mode: 0o777 });
+
+ const fileInfo = await Deno.stat(filename);
+ await Deno.remove(filename);
+ assert(fileInfo && fileInfo.mode);
+ assertEquals(fileInfo.mode & 0o777, 0o777);
+});
+
+test("Mode is not set when rid is passed", async function testCorrectFileModeRid() {
+ if (Deno.build.os === "windows") return;
+
+ const filename: string = await Deno.makeTempFile();
+ const file: Deno.File = await Deno.open(filename, {
+ create: true,
+ write: true,
+ read: true,
+ });
+
+ await writeFile(file.rid, "hello world", { mode: 0o777 });
+ Deno.close(file.rid);
+
+ const fileInfo = await Deno.stat(filename);
+ await Deno.remove(filename);
+ assert(fileInfo.mode);
+ assertNotEquals(fileInfo.mode & 0o777, 0o777);
+});
+
+test("Mode is not implemented on windows", function testModeNotImplementedWindows(): void {
+ if (Deno.build.os !== "windows") return;
+
+ assertThrowsAsync(
+ async () => {
+ await writeFile("fail.txt", "some data", { mode: 0o777 });
+ },
+ Error,
+ `Not implemented: "mode" on Windows`
+ );
+});
diff --git a/std/node/_fs/promises/mod.ts b/std/node/_fs/promises/mod.ts
new file mode 100644
index 000000000..3cb81a422
--- /dev/null
+++ b/std/node/_fs/promises/mod.ts
@@ -0,0 +1 @@
+export { writeFile } from "./_fs_writeFile.ts";
diff --git a/std/node/fs.ts b/std/node/fs.ts
index 343786e24..737f2a0e9 100755
--- a/std/node/fs.ts
+++ b/std/node/fs.ts
@@ -11,6 +11,8 @@ import { readlink, readlinkSync } from "./_fs/_fs_readlink.ts";
import { exists, existsSync } from "./_fs/_fs_exists.ts";
import { mkdir, mkdirSync } from "./_fs/_fs_mkdir.ts";
import { copyFile, copyFileSync } from "./_fs/_fs_copy.ts";
+import { writeFile } from "./_fs/_fs_writeFile.ts";
+import * as promises from "./_fs/promises/mod.ts";
export {
access,
@@ -34,4 +36,6 @@ export {
readlinkSync,
mkdir,
mkdirSync,
+ writeFile,
+ promises,
};