diff options
author | Marcos Casagrande <marcoscvp90@gmail.com> | 2020-05-05 00:59:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-04 18:59:37 -0400 |
commit | f0aea98c85e18b297593ed6483b620945483fa37 (patch) | |
tree | 4176b47a2162e2713169a1d7858fdb6aec3a4ed5 | |
parent | 5f67a202ff59f25ea183c261f664a6db06407e17 (diff) |
feat(std/node): fs.writefile / fs.promises.writeFile (#5054)
-rw-r--r-- | std/node/_fs/_fs_appendFile.ts | 92 | ||||
-rw-r--r-- | std/node/_fs/_fs_common.ts | 124 | ||||
-rw-r--r-- | std/node/_fs/_fs_copy_test.ts | 2 | ||||
-rw-r--r-- | std/node/_fs/_fs_readFile.ts | 39 | ||||
-rw-r--r-- | std/node/_fs/_fs_writeFile.ts | 65 | ||||
-rw-r--r-- | std/node/_fs/_fs_writeFile_test.ts | 180 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_writeFile.ts | 17 | ||||
-rw-r--r-- | std/node/_fs/promises/_fs_writeFile_test.ts | 119 | ||||
-rw-r--r-- | std/node/_fs/promises/mod.ts | 1 | ||||
-rwxr-xr-x | std/node/fs.ts | 4 |
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, }; |