summaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
Diffstat (limited to 'std')
-rw-r--r--std/node/_fs/_fs_lstat.ts59
-rw-r--r--std/node/_fs/_fs_lstat_test.ts56
-rw-r--r--std/node/_fs/_fs_open.ts103
-rw-r--r--std/node/_fs/_fs_open_test.ts217
-rw-r--r--std/node/_fs/_fs_readdir.ts117
-rw-r--r--std/node/_fs/_fs_readdir_test.ts59
-rw-r--r--std/node/_fs/_fs_rename.ts23
-rw-r--r--std/node/_fs/_fs_rename_test.ts34
-rw-r--r--std/node/_fs/_fs_rmdir.ts36
-rw-r--r--std/node/_fs/_fs_rmdir_test.ts66
-rw-r--r--std/node/_fs/_fs_stat.ts284
-rw-r--r--std/node/_fs/_fs_stat_test.ts107
-rw-r--r--std/node/_fs/_fs_unlink.ts10
-rw-r--r--std/node/_fs/_fs_unlink_test.ts30
-rw-r--r--std/node/_fs/_fs_watch.ts111
-rw-r--r--std/node/_fs/_fs_watch_test.ts29
-rw-r--r--std/node/fs.ts25
17 files changed, 1366 insertions, 0 deletions
diff --git a/std/node/_fs/_fs_lstat.ts b/std/node/_fs/_fs_lstat.ts
new file mode 100644
index 000000000..0b79fb665
--- /dev/null
+++ b/std/node/_fs/_fs_lstat.ts
@@ -0,0 +1,59 @@
+import {
+ BigIntStats,
+ CFISBIS,
+ statCallback,
+ statCallbackBigInt,
+ statOptions,
+ Stats,
+} from "./_fs_stat.ts";
+
+export function lstat(path: string | URL, callback: statCallback): void;
+export function lstat(
+ path: string | URL,
+ options: { bigint: false },
+ callback: statCallback,
+): void;
+export function lstat(
+ path: string | URL,
+ options: { bigint: true },
+ callback: statCallbackBigInt,
+): void;
+export function lstat(
+ path: string | URL,
+ optionsOrCallback: statCallback | statCallbackBigInt | statOptions,
+ maybeCallback?: statCallback | statCallbackBigInt,
+) {
+ const callback =
+ (typeof optionsOrCallback === "function"
+ ? optionsOrCallback
+ : maybeCallback) as (
+ err: Error | undefined,
+ stat: BigIntStats | Stats,
+ ) => void;
+ const options = typeof optionsOrCallback === "object"
+ ? optionsOrCallback
+ : { bigint: false };
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ Deno.lstat(path)
+ .then((stat) => callback(undefined, CFISBIS(stat, options.bigint)))
+ .catch((err) => callback(err, err));
+}
+
+export function lstatSync(path: string | URL): Stats;
+export function lstatSync(
+ path: string | URL,
+ options: { bigint: false },
+): Stats;
+export function lstatSync(
+ path: string | URL,
+ options: { bigint: true },
+): BigIntStats;
+export function lstatSync(
+ path: string | URL,
+ options?: statOptions,
+): Stats | BigIntStats {
+ const origin = Deno.lstatSync(path);
+ return CFISBIS(origin, options?.bigint || false);
+}
diff --git a/std/node/_fs/_fs_lstat_test.ts b/std/node/_fs/_fs_lstat_test.ts
new file mode 100644
index 000000000..1da0a562f
--- /dev/null
+++ b/std/node/_fs/_fs_lstat_test.ts
@@ -0,0 +1,56 @@
+import { lstat, lstatSync } from "./_fs_lstat.ts";
+import { fail } from "../../testing/asserts.ts";
+import { assertStats, assertStatsBigInt } from "./_fs_stat_test.ts";
+import type { BigIntStats, Stats } from "./_fs_stat.ts";
+
+Deno.test({
+ name: "ASYNC: get a file Stats (lstat)",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ await new Promise<Stats>((resolve, reject) => {
+ lstat(file, (err, stat) => {
+ if (err) reject(err);
+ resolve(stat);
+ });
+ })
+ .then((stat) => {
+ assertStats(stat, Deno.lstatSync(file));
+ })
+ .catch(() => fail())
+ .finally(() => {
+ Deno.removeSync(file);
+ });
+ },
+});
+
+Deno.test({
+ name: "SYNC: get a file Stats (lstat)",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertStats(lstatSync(file), Deno.lstatSync(file));
+ },
+});
+
+Deno.test({
+ name: "ASYNC: get a file BigInt Stats (lstat)",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ await new Promise<BigIntStats>((resolve, reject) => {
+ lstat(file, { bigint: true }, (err, stat) => {
+ if (err) reject(err);
+ resolve(stat);
+ });
+ })
+ .then((stat) => assertStatsBigInt(stat, Deno.lstatSync(file)))
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(file));
+ },
+});
+
+Deno.test({
+ name: "SYNC: BigInt Stats (lstat)",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertStatsBigInt(lstatSync(file, { bigint: true }), Deno.lstatSync(file));
+ },
+});
diff --git a/std/node/_fs/_fs_open.ts b/std/node/_fs/_fs_open.ts
new file mode 100644
index 000000000..bf53115de
--- /dev/null
+++ b/std/node/_fs/_fs_open.ts
@@ -0,0 +1,103 @@
+import { existsSync } from "../../fs/mod.ts";
+import { fromFileUrl } from "../path.ts";
+import { getOpenOptions } from "./_fs_common.ts";
+
+type openFlags =
+ | "a"
+ | "ax"
+ | "a+"
+ | "ax+"
+ | "as"
+ | "as+"
+ | "r"
+ | "r+"
+ | "rs+"
+ | "w"
+ | "wx"
+ | "w+"
+ | "wx+";
+
+type openCallback = (err: Error | undefined, fd: number) => void;
+
+function convertFlagAndModeToOptions(
+ flag?: openFlags,
+ mode?: number,
+): Deno.OpenOptions | undefined {
+ if (!flag && !mode) return undefined;
+ if (!flag && mode) return { mode };
+ return { ...getOpenOptions(flag), mode };
+}
+
+export function open(path: string | URL, callback: openCallback): void;
+export function open(
+ path: string | URL,
+ flags: openFlags,
+ callback: openCallback,
+): void;
+export function open(
+ path: string | URL,
+ flags: openFlags,
+ mode: number,
+ callback: openCallback,
+): void;
+export function open(
+ path: string | URL,
+ flagsOrCallback: openCallback | openFlags,
+ callbackOrMode?: openCallback | number,
+ maybeCallback?: openCallback,
+) {
+ const flags = typeof flagsOrCallback === "string"
+ ? flagsOrCallback
+ : undefined;
+ const callback = typeof flagsOrCallback === "function"
+ ? flagsOrCallback
+ : typeof callbackOrMode === "function"
+ ? callbackOrMode
+ : maybeCallback;
+ const mode = typeof callbackOrMode === "number" ? callbackOrMode : undefined;
+ path = path instanceof URL ? fromFileUrl(path) : path;
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ if (["ax", "ax+", "wx", "wx+"].includes(flags || "") && existsSync(path)) {
+ const err = new Error(`EEXIST: file already exists, open '${path}'`);
+ callback(err, 0);
+ } else {
+ if (flags === "as" || flags === "as+") {
+ try {
+ const res = openSync(path, flags, mode);
+ callback(undefined, res);
+ } catch (error) {
+ callback(error, error);
+ }
+ return;
+ }
+ Deno.open(path, convertFlagAndModeToOptions(flags, mode))
+ .then((file) => callback(undefined, file.rid))
+ .catch((err) => callback(err, err));
+ }
+}
+
+export function openSync(path: string | URL): number;
+export function openSync(path: string | URL, flags?: openFlags): number;
+export function openSync(path: string | URL, mode?: number): number;
+export function openSync(
+ path: string | URL,
+ flags?: openFlags,
+ mode?: number,
+): number;
+export function openSync(
+ path: string | URL,
+ flagsOrMode?: openFlags | number,
+ maybeMode?: number,
+) {
+ const flags = typeof flagsOrMode === "string" ? flagsOrMode : undefined;
+ const mode = typeof flagsOrMode === "number" ? flagsOrMode : maybeMode;
+ path = path instanceof URL ? fromFileUrl(path) : path;
+
+ if (["ax", "ax+", "wx", "wx+"].includes(flags || "") && existsSync(path)) {
+ throw new Error(`EEXIST: file already exists, open '${path}'`);
+ }
+
+ return Deno.openSync(path, convertFlagAndModeToOptions(flags, mode)).rid;
+}
diff --git a/std/node/_fs/_fs_open_test.ts b/std/node/_fs/_fs_open_test.ts
new file mode 100644
index 000000000..d83ce772d
--- /dev/null
+++ b/std/node/_fs/_fs_open_test.ts
@@ -0,0 +1,217 @@
+import {
+ assert,
+ assertEquals,
+ assertThrows,
+ fail,
+} from "../../testing/asserts.ts";
+import { open, openSync } from "./_fs_open.ts";
+import { join, parse } from "../../path/mod.ts";
+import { existsSync } from "../../fs/mod.ts";
+import { closeSync } from "./_fs_close.ts";
+
+const temp_dir = parse(Deno.makeTempFileSync()).dir;
+
+Deno.test({
+ name: "ASYNC: open file",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ let fd1: number;
+ await new Promise<number>((resolve, reject) => {
+ open(file, (err, fd) => {
+ if (err) reject(err);
+ resolve(fd);
+ });
+ })
+ .then((fd) => {
+ fd1 = fd;
+ assert(Deno.resources()[fd], `${fd}`);
+ })
+ .catch(() => fail())
+ .finally(() => closeSync(fd1));
+ },
+});
+
+Deno.test({
+ name: "SYNC: open file",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ const fd = openSync(file);
+ assert(Deno.resources()[fd]);
+ closeSync(fd);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'a'",
+ fn() {
+ const file = join(temp_dir, "some_random_file");
+ const fd = openSync(file, "a");
+ assertEquals(typeof fd, "number");
+ assertEquals(existsSync(file), true);
+ assert(Deno.resources()[fd]);
+ closeSync(fd);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'ax'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertThrows(
+ () => {
+ openSync(file, "ax");
+ },
+ Error,
+ `EEXIST: file already exists, open '${file}'`,
+ );
+ Deno.removeSync(file);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'a+'",
+ fn() {
+ const file = join(temp_dir, "some_random_file2");
+ const fd = openSync(file, "a+");
+ assertEquals(typeof fd, "number");
+ assertEquals(existsSync(file), true);
+ closeSync(fd);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'ax+'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertThrows(
+ () => {
+ openSync(file, "ax+");
+ },
+ Error,
+ `EEXIST: file already exists, open '${file}'`,
+ );
+ Deno.removeSync(file);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'as'",
+ fn() {
+ const file = join(temp_dir, "some_random_file10");
+ const fd = openSync(file, "as");
+ assertEquals(existsSync(file), true);
+ assertEquals(typeof fd, "number");
+ closeSync(fd);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'as+'",
+ fn() {
+ const file = join(temp_dir, "some_random_file10");
+ const fd = openSync(file, "as+");
+ assertEquals(existsSync(file), true);
+ assertEquals(typeof fd, "number");
+ closeSync(fd);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'r'",
+ fn() {
+ const file = join(temp_dir, "some_random_file3");
+ assertThrows(
+ () => {
+ openSync(file, "r");
+ },
+ Error,
+ "No such file or directory (os error 2)",
+ );
+ },
+});
+
+Deno.test({
+ name: "open with flag 'r+'",
+ fn() {
+ const file = join(temp_dir, "some_random_file4");
+ assertThrows(
+ () => {
+ openSync(file, "r+");
+ },
+ Error,
+ "No such file or directory (os error 2)",
+ );
+ },
+});
+
+Deno.test({
+ name: "open with flag 'w'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ Deno.writeTextFileSync(file, "hi there");
+ const fd = openSync(file, "w");
+ assertEquals(typeof fd, "number");
+ assertEquals(Deno.readTextFileSync(file), "");
+ closeSync(fd);
+
+ const file2 = join(temp_dir, "some_random_file5");
+ const fd2 = openSync(file2, "w");
+ assertEquals(typeof fd2, "number");
+ assertEquals(existsSync(file2), true);
+ closeSync(fd2);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'wx'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ Deno.writeTextFileSync(file, "hi there");
+ const fd = openSync(file, "w");
+ assertEquals(typeof fd, "number");
+ assertEquals(Deno.readTextFileSync(file), "");
+ closeSync(fd);
+
+ const file2 = Deno.makeTempFileSync();
+ assertThrows(
+ () => {
+ openSync(file2, "wx");
+ },
+ Error,
+ `EEXIST: file already exists, open '${file2}'`,
+ );
+ },
+});
+
+Deno.test({
+ name: "open with flag 'w+'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ Deno.writeTextFileSync(file, "hi there");
+ const fd = openSync(file, "w+");
+ assertEquals(typeof fd, "number");
+ assertEquals(Deno.readTextFileSync(file), "");
+ closeSync(fd);
+
+ const file2 = join(temp_dir, "some_random_file6");
+ const fd2 = openSync(file2, "w+");
+ assertEquals(typeof fd2, "number");
+ assertEquals(existsSync(file2), true);
+ closeSync(fd2);
+ },
+});
+
+Deno.test({
+ name: "open with flag 'wx+'",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertThrows(
+ () => {
+ openSync(file, "wx+");
+ },
+ Error,
+ `EEXIST: file already exists, open '${file}'`,
+ );
+ Deno.removeSync(file);
+ },
+});
diff --git a/std/node/_fs/_fs_readdir.ts b/std/node/_fs/_fs_readdir.ts
new file mode 100644
index 000000000..9034eccf8
--- /dev/null
+++ b/std/node/_fs/_fs_readdir.ts
@@ -0,0 +1,117 @@
+import { asyncIterableToCallback } from "./_fs_watch.ts";
+import Dirent from "./_fs_dirent.ts";
+import { fromFileUrl } from "../path.ts";
+
+function toDirent(val: Deno.DirEntry): Dirent {
+ return new Dirent(val);
+}
+
+type readDirOptions = {
+ encoding?: string;
+ withFileTypes?: boolean;
+};
+
+type readDirCallback = (err: Error | undefined, files: string[]) => void;
+
+type readDirCallbackDirent = (err: Error | undefined, files: Dirent[]) => void;
+
+type readDirBoth = (
+ err: Error | undefined,
+ files: string[] | Dirent[] | Array<string | Dirent>,
+) => void;
+
+export function readdir(
+ path: string | URL,
+ options: { withFileTypes?: false; encoding?: string },
+ callback: readDirCallback,
+): void;
+export function readdir(
+ path: string | URL,
+ options: { withFileTypes: true; encoding?: string },
+ callback: readDirCallbackDirent,
+): void;
+export function readdir(path: string | URL, callback: readDirCallback): void;
+export function readdir(
+ path: string | URL,
+ optionsOrCallback: readDirOptions | readDirCallback | readDirCallbackDirent,
+ maybeCallback?: readDirCallback | readDirCallbackDirent,
+) {
+ const callback =
+ (typeof optionsOrCallback === "function"
+ ? optionsOrCallback
+ : maybeCallback) as readDirBoth | undefined;
+ const options = typeof optionsOrCallback === "object"
+ ? optionsOrCallback
+ : null;
+ const result: Array<string | Dirent> = [];
+ path = path instanceof URL ? fromFileUrl(path) : path;
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ if (options?.encoding) {
+ try {
+ new TextDecoder(options.encoding);
+ } catch (error) {
+ throw new Error(
+ `TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "${options.encoding}" is invalid for option "encoding"`,
+ );
+ }
+ }
+
+ try {
+ asyncIterableToCallback(Deno.readDir(path), (val, done) => {
+ if (typeof path !== "string") return;
+ if (done) {
+ callback(undefined, result);
+ return;
+ }
+ if (options?.withFileTypes) {
+ result.push(toDirent(val));
+ } else result.push(decode(val.name));
+ });
+ } catch (error) {
+ callback(error, result);
+ }
+}
+
+function decode(str: string, encoding?: string): string {
+ if (!encoding) return str;
+ else {
+ const decoder = new TextDecoder(encoding);
+ const encoder = new TextEncoder();
+ return decoder.decode(encoder.encode(str));
+ }
+}
+
+export function readdirSync(
+ path: string | URL,
+ options: { withFileTypes: true; encoding?: string },
+): Dirent[];
+export function readdirSync(
+ path: string | URL,
+ options?: { withFileTypes?: false; encoding?: string },
+): string[];
+export function readdirSync(
+ path: string | URL,
+ options?: readDirOptions,
+): Array<string | Dirent> {
+ const result = [];
+ path = path instanceof URL ? fromFileUrl(path) : path;
+
+ if (options?.encoding) {
+ try {
+ new TextDecoder(options.encoding);
+ } catch (error) {
+ throw new Error(
+ `TypeError [ERR_INVALID_OPT_VALUE_ENCODING]: The value "${options.encoding}" is invalid for option "encoding"`,
+ );
+ }
+ }
+
+ for (const file of Deno.readDirSync(path)) {
+ if (options?.withFileTypes) {
+ result.push(toDirent(file));
+ } else result.push(decode(file.name));
+ }
+ return result;
+}
diff --git a/std/node/_fs/_fs_readdir_test.ts b/std/node/_fs/_fs_readdir_test.ts
new file mode 100644
index 000000000..c15b9ebe0
--- /dev/null
+++ b/std/node/_fs/_fs_readdir_test.ts
@@ -0,0 +1,59 @@
+import { assertEquals, fail } from "../../testing/asserts.ts";
+import { readdir, readdirSync } from "./_fs_readdir.ts";
+import { join } from "../../path/mod.ts";
+
+Deno.test({
+ name: "ASYNC: reading empty directory",
+ async fn() {
+ const dir = Deno.makeTempDirSync();
+ await new Promise<string[]>((resolve, reject) => {
+ readdir(dir, (err, files) => {
+ if (err) reject(err);
+ resolve(files);
+ });
+ })
+ .then((files) => assertEquals(files, []))
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(dir));
+ },
+});
+
+Deno.test({
+ name: "ASYNC: reading non-empty directory",
+ async fn() {
+ const dir = Deno.makeTempDirSync();
+ Deno.writeTextFileSync(join(dir, "file1.txt"), "hi");
+ Deno.writeTextFileSync(join(dir, "file2.txt"), "hi");
+ Deno.mkdirSync(join(dir, "some_dir"));
+ await new Promise((resolve, reject) => {
+ readdir(dir, (err, files) => {
+ if (err) reject(err);
+ resolve(files);
+ });
+ })
+ .then((files) =>
+ assertEquals(files, ["file1.txt", "some_dir", "file2.txt"])
+ )
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(dir, { recursive: true }));
+ },
+});
+
+Deno.test({
+ name: "SYNC: reading empty the directory",
+ fn() {
+ const dir = Deno.makeTempDirSync();
+ assertEquals(readdirSync(dir), []);
+ },
+});
+
+Deno.test({
+ name: "SYNC: reading a non-empty directory",
+ fn() {
+ const dir = Deno.makeTempDirSync();
+ Deno.writeTextFileSync(join(dir, "file1.txt"), "hi");
+ Deno.writeTextFileSync(join(dir, "file2.txt"), "hi");
+ Deno.mkdirSync(join(dir, "some_dir"));
+ assertEquals(readdirSync(dir), ["file1.txt", "some_dir", "file2.txt"]);
+ },
+});
diff --git a/std/node/_fs/_fs_rename.ts b/std/node/_fs/_fs_rename.ts
new file mode 100644
index 000000000..ee7c00977
--- /dev/null
+++ b/std/node/_fs/_fs_rename.ts
@@ -0,0 +1,23 @@
+import { fromFileUrl } from "../path.ts";
+
+export function rename(
+ oldPath: string | URL,
+ newPath: string | URL,
+ callback: (err?: Error) => void,
+) {
+ oldPath = oldPath instanceof URL ? fromFileUrl(oldPath) : oldPath;
+ newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath;
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ Deno.rename(oldPath, newPath)
+ .then((_) => callback())
+ .catch(callback);
+}
+
+export function renameSync(oldPath: string | URL, newPath: string | URL) {
+ oldPath = oldPath instanceof URL ? fromFileUrl(oldPath) : oldPath;
+ newPath = newPath instanceof URL ? fromFileUrl(newPath) : newPath;
+
+ Deno.renameSync(oldPath, newPath);
+}
diff --git a/std/node/_fs/_fs_rename_test.ts b/std/node/_fs/_fs_rename_test.ts
new file mode 100644
index 000000000..c8622e4ef
--- /dev/null
+++ b/std/node/_fs/_fs_rename_test.ts
@@ -0,0 +1,34 @@
+import { assertEquals, fail } from "../../testing/asserts.ts";
+import { rename, renameSync } from "./_fs_rename.ts";
+import { existsSync } from "../../fs/mod.ts";
+import { join, parse } from "../../path/mod.ts";
+
+Deno.test({
+ name: "ASYNC: renaming a file",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ const newPath = join(parse(file).dir, `${parse(file).base}_renamed`);
+ await new Promise((resolve, reject) => {
+ rename(file, newPath, (err) => {
+ if (err) reject(err);
+ });
+ })
+ .then(() => {
+ assertEquals(existsSync(newPath), true);
+ assertEquals(existsSync(file), false);
+ })
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(file));
+ },
+});
+
+Deno.test({
+ name: "SYNC: renaming a file",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ const newPath = join(parse(file).dir, `${parse(file).base}_renamed`);
+ renameSync(file, newPath);
+ assertEquals(existsSync(newPath), true);
+ assertEquals(existsSync(file), false);
+ },
+});
diff --git a/std/node/_fs/_fs_rmdir.ts b/std/node/_fs/_fs_rmdir.ts
new file mode 100644
index 000000000..2035a1e71
--- /dev/null
+++ b/std/node/_fs/_fs_rmdir.ts
@@ -0,0 +1,36 @@
+type rmdirOptions = {
+ maxRetries?: number;
+ recursive?: boolean;
+ retryDelay?: number;
+};
+
+type rmdirCallback = (err?: Error) => void;
+
+export function rmdir(path: string | URL, callback: rmdirCallback): void;
+export function rmdir(
+ path: string | URL,
+ options: rmdirOptions,
+ callback: rmdirCallback,
+): void;
+export function rmdir(
+ path: string | URL,
+ optionsOrCallback: rmdirOptions | rmdirCallback,
+ maybeCallback?: rmdirCallback,
+) {
+ const callback = typeof optionsOrCallback === "function"
+ ? optionsOrCallback
+ : maybeCallback;
+ const options = typeof optionsOrCallback === "object"
+ ? optionsOrCallback
+ : undefined;
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ Deno.remove(path, { recursive: options?.recursive })
+ .then((_) => callback())
+ .catch(callback);
+}
+
+export function rmdirSync(path: string | URL, options?: rmdirOptions) {
+ Deno.removeSync(path, { recursive: options?.recursive });
+}
diff --git a/std/node/_fs/_fs_rmdir_test.ts b/std/node/_fs/_fs_rmdir_test.ts
new file mode 100644
index 000000000..ee25d25f8
--- /dev/null
+++ b/std/node/_fs/_fs_rmdir_test.ts
@@ -0,0 +1,66 @@
+import { assertEquals, fail } from "../../testing/asserts.ts";
+import { rmdir, rmdirSync } from "./_fs_rmdir.ts";
+import { existsSync } from "../../fs/mod.ts";
+import { join } from "../../path/mod.ts";
+
+Deno.test({
+ name: "ASYNC: removing empty folder",
+ async fn() {
+ const dir = Deno.makeTempDirSync();
+ await new Promise((resolve, reject) => {
+ rmdir(dir, (err) => {
+ if (err) reject(err);
+ resolve();
+ });
+ })
+ .then(() => assertEquals(existsSync(dir), false))
+ .catch(() => fail())
+ .finally(() => {
+ if (existsSync(dir)) Deno.removeSync(dir);
+ });
+ },
+});
+
+Deno.test({
+ name: "SYNC: removing empty folder",
+ fn() {
+ const dir = Deno.makeTempDirSync();
+ rmdirSync(dir);
+ assertEquals(existsSync(dir), false);
+ },
+});
+
+Deno.test({
+ name: "ASYNC: removing non-empty folder",
+ async fn() {
+ const dir = Deno.makeTempDirSync();
+ Deno.createSync(join(dir, "file1.txt"));
+ Deno.createSync(join(dir, "file2.txt"));
+ Deno.mkdirSync(join(dir, "some_dir"));
+ Deno.createSync(join(dir, "some_dir", "file.txt"));
+ await new Promise((resolve, reject) => {
+ rmdir(dir, { recursive: true }, (err) => {
+ if (err) reject(err);
+ resolve();
+ });
+ })
+ .then(() => assertEquals(existsSync(dir), false))
+ .catch(() => fail())
+ .finally(() => {
+ if (existsSync(dir)) Deno.removeSync(dir, { recursive: true });
+ });
+ },
+});
+
+Deno.test({
+ name: "SYNC: removing non-empty folder",
+ fn() {
+ const dir = Deno.makeTempDirSync();
+ Deno.createSync(join(dir, "file1.txt"));
+ Deno.createSync(join(dir, "file2.txt"));
+ Deno.mkdirSync(join(dir, "some_dir"));
+ Deno.createSync(join(dir, "some_dir", "file.txt"));
+ rmdirSync(dir, { recursive: true });
+ assertEquals(existsSync(dir), false);
+ },
+});
diff --git a/std/node/_fs/_fs_stat.ts b/std/node/_fs/_fs_stat.ts
new file mode 100644
index 000000000..885b368c1
--- /dev/null
+++ b/std/node/_fs/_fs_stat.ts
@@ -0,0 +1,284 @@
+export type statOptions = {
+ bigint: boolean;
+};
+
+export type Stats = {
+ /** ID of the device containing the file.
+ *
+ * _Linux/Mac OS only._ */
+ dev: number | null;
+ /** Inode number.
+ *
+ * _Linux/Mac OS only._ */
+ ino: number | null;
+ /** **UNSTABLE**: Match behavior with Go on Windows for `mode`.
+ *
+ * The underlying raw `st_mode` bits that contain the standard Unix
+ * permissions for this file/directory. */
+ mode: number | null;
+ /** Number of hard links pointing to this file.
+ *
+ * _Linux/Mac OS only._ */
+ nlink: number | null;
+ /** User ID of the owner of this file.
+ *
+ * _Linux/Mac OS only._ */
+ uid: number | null;
+ /** Group ID of the owner of this file.
+ *
+ * _Linux/Mac OS only._ */
+ gid: number | null;
+ /** Device ID of this file.
+ *
+ * _Linux/Mac OS only._ */
+ rdev: number | null;
+ /** The size of the file, in bytes. */
+ size: number;
+ /** Blocksize for filesystem I/O.
+ *
+ * _Linux/Mac OS only._ */
+ blksize: number | null;
+ /** Number of blocks allocated to the file, in 512-byte units.
+ *
+ * _Linux/Mac OS only._ */
+ blocks: number | null;
+ /** The last modification time of the file. This corresponds to the `mtime`
+ * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This
+ * may not be available on all platforms. */
+ mtime: Date | null;
+ /** The last access time of the file. This corresponds to the `atime`
+ * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not
+ * be available on all platforms. */
+ atime: Date | null;
+ /** The creation time of the file. This corresponds to the `birthtime`
+ * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may
+ * not be available on all platforms. */
+ birthtime: Date | null;
+ /** change time */
+ ctime: Date | null;
+ /** atime in milliseconds */
+ atimeMs: number | null;
+ /** atime in milliseconds */
+ mtimeMs: number | null;
+ /** atime in milliseconds */
+ ctimeMs: number | null;
+ /** atime in milliseconds */
+ birthtimeMs: number | null;
+ isBlockDevice: () => boolean;
+ isCharacterDevice: () => boolean;
+ isDirectory: () => boolean;
+ isFIFO: () => boolean;
+ isFile: () => boolean;
+ isSocket: () => boolean;
+ isSymbolicLink: () => boolean;
+};
+
+export type BigIntStats = {
+ /** ID of the device containing the file.
+ *
+ * _Linux/Mac OS only._ */
+ dev: BigInt | null;
+ /** Inode number.
+ *
+ * _Linux/Mac OS only._ */
+ ino: BigInt | null;
+ /** **UNSTABLE**: Match behavior with Go on Windows for `mode`.
+ *
+ * The underlying raw `st_mode` bits that contain the standard Unix
+ * permissions for this file/directory. */
+ mode: BigInt | null;
+ /** Number of hard links pointing to this file.
+ *
+ * _Linux/Mac OS only._ */
+ nlink: BigInt | null;
+ /** User ID of the owner of this file.
+ *
+ * _Linux/Mac OS only._ */
+ uid: BigInt | null;
+ /** Group ID of the owner of this file.
+ *
+ * _Linux/Mac OS only._ */
+ gid: BigInt | null;
+ /** Device ID of this file.
+ *
+ * _Linux/Mac OS only._ */
+ rdev: BigInt | null;
+ /** The size of the file, in bytes. */
+ size: BigInt;
+ /** Blocksize for filesystem I/O.
+ *
+ * _Linux/Mac OS only._ */
+ blksize: BigInt | null;
+ /** Number of blocks allocated to the file, in 512-byte units.
+ *
+ * _Linux/Mac OS only._ */
+ blocks: BigInt | null;
+ /** The last modification time of the file. This corresponds to the `mtime`
+ * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This
+ * may not be available on all platforms. */
+ mtime: Date | null;
+ /** The last access time of the file. This corresponds to the `atime`
+ * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not
+ * be available on all platforms. */
+ atime: Date | null;
+ /** The creation time of the file. This corresponds to the `birthtime`
+ * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may
+ * not be available on all platforms. */
+ birthtime: Date | null;
+ /** change time */
+ ctime: Date | null;
+ /** atime in milliseconds */
+ atimeMs: BigInt | null;
+ /** atime in milliseconds */
+ mtimeMs: BigInt | null;
+ /** atime in milliseconds */
+ ctimeMs: BigInt | null;
+ /** atime in nanoseconds */
+ birthtimeMs: BigInt | null;
+ /** atime in nanoseconds */
+ atimeNs: BigInt | null;
+ /** atime in nanoseconds */
+ mtimeNs: BigInt | null;
+ /** atime in nanoseconds */
+ ctimeNs: BigInt | null;
+ /** atime in nanoseconds */
+ birthtimeNs: BigInt | null;
+ isBlockDevice: () => boolean;
+ isCharacterDevice: () => boolean;
+ isDirectory: () => boolean;
+ isFIFO: () => boolean;
+ isFile: () => boolean;
+ isSocket: () => boolean;
+ isSymbolicLink: () => boolean;
+};
+
+export function convertFileInfoToStats(origin: Deno.FileInfo): Stats {
+ return {
+ dev: origin.dev,
+ ino: origin.ino,
+ mode: origin.mode,
+ nlink: origin.nlink,
+ uid: origin.uid,
+ gid: origin.gid,
+ rdev: origin.rdev,
+ size: origin.size,
+ blksize: origin.blksize,
+ blocks: origin.blocks,
+ mtime: origin.mtime,
+ atime: origin.atime,
+ birthtime: origin.birthtime,
+ mtimeMs: origin.mtime?.getTime() || null,
+ atimeMs: origin.atime?.getTime() || null,
+ birthtimeMs: origin.birthtime?.getTime() || null,
+ isFile: () => origin.isFile,
+ isDirectory: () => origin.isDirectory,
+ isSymbolicLink: () => origin.isSymlink,
+ // not sure about those
+ isBlockDevice: () => false,
+ isFIFO: () => false,
+ isCharacterDevice: () => false,
+ isSocket: () => false,
+ ctime: origin.mtime,
+ ctimeMs: origin.mtime?.getTime() || null,
+ };
+}
+
+export function convertFileInfoToBigIntStats(
+ origin: Deno.FileInfo,
+): BigIntStats {
+ return {
+ dev: BigInt(origin.dev),
+ ino: BigInt(origin.ino),
+ mode: BigInt(origin.mode),
+ nlink: BigInt(origin.nlink),
+ uid: BigInt(origin.uid),
+ gid: BigInt(origin.gid),
+ rdev: BigInt(origin.rdev),
+ size: BigInt(origin.size),
+ blksize: BigInt(origin.blksize),
+ blocks: BigInt(origin.blocks),
+ mtime: origin.mtime,
+ atime: origin.atime,
+ birthtime: origin.birthtime,
+ mtimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null,
+ atimeMs: origin.atime ? BigInt(origin.atime.getTime()) : null,
+ birthtimeMs: origin.birthtime ? BigInt(origin.birthtime.getTime()) : null,
+ mtimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null,
+ atimeNs: origin.atime ? BigInt(origin.atime.getTime()) * 1000000n : null,
+ birthtimeNs: origin.birthtime
+ ? BigInt(origin.birthtime.getTime()) * 1000000n
+ : null,
+ isFile: () => origin.isFile,
+ isDirectory: () => origin.isDirectory,
+ isSymbolicLink: () => origin.isSymlink,
+ // not sure about those
+ isBlockDevice: () => false,
+ isFIFO: () => false,
+ isCharacterDevice: () => false,
+ isSocket: () => false,
+ ctime: origin.mtime,
+ ctimeMs: origin.mtime ? BigInt(origin.mtime.getTime()) : null,
+ ctimeNs: origin.mtime ? BigInt(origin.mtime.getTime()) * 1000000n : null,
+ };
+}
+
+// shortcut for Convert File Info to Stats or BigIntStats
+export function CFISBIS(fileInfo: Deno.FileInfo, bigInt: boolean) {
+ if (bigInt) return convertFileInfoToBigIntStats(fileInfo);
+ return convertFileInfoToStats(fileInfo);
+}
+
+export type statCallbackBigInt = (
+ err: Error | undefined,
+ stat: BigIntStats,
+) => void;
+
+export type statCallback = (err: Error | undefined, stat: Stats) => void;
+
+export function stat(path: string | URL, callback: statCallback): void;
+export function stat(
+ path: string | URL,
+ options: { bigint: false },
+ callback: statCallback,
+): void;
+export function stat(
+ path: string | URL,
+ options: { bigint: true },
+ callback: statCallbackBigInt,
+): void;
+export function stat(
+ path: string | URL,
+ optionsOrCallback: statCallback | statCallbackBigInt | statOptions,
+ maybeCallback?: statCallback | statCallbackBigInt,
+) {
+ const callback =
+ (typeof optionsOrCallback === "function"
+ ? optionsOrCallback
+ : maybeCallback) as (
+ err: Error | undefined,
+ stat: BigIntStats | Stats,
+ ) => void;
+ const options = typeof optionsOrCallback === "object"
+ ? optionsOrCallback
+ : { bigint: false };
+
+ if (!callback) throw new Error("No callback function supplied");
+
+ Deno.stat(path)
+ .then((stat) => callback(undefined, CFISBIS(stat, options.bigint)))
+ .catch((err) => callback(err, err));
+}
+
+export function statSync(path: string | URL): Stats;
+export function statSync(path: string | URL, options: { bigint: false }): Stats;
+export function statSync(
+ path: string | URL,
+ options: { bigint: true },
+): BigIntStats;
+export function statSync(
+ path: string | URL,
+ options: statOptions = { bigint: false },
+): Stats | BigIntStats {
+ const origin = Deno.statSync(path);
+ return CFISBIS(origin, options.bigint);
+}
diff --git a/std/node/_fs/_fs_stat_test.ts b/std/node/_fs/_fs_stat_test.ts
new file mode 100644
index 000000000..7e352987a
--- /dev/null
+++ b/std/node/_fs/_fs_stat_test.ts
@@ -0,0 +1,107 @@
+import { BigIntStats, stat, Stats, statSync } from "./_fs_stat.ts";
+import { assertEquals, fail } from "../../testing/asserts.ts";
+
+export function assertStats(actual: Stats, expected: Deno.FileInfo) {
+ assertEquals(actual.dev, expected.dev);
+ assertEquals(actual.gid, expected.gid);
+ assertEquals(actual.size, expected.size);
+ assertEquals(actual.blksize, expected.blksize);
+ assertEquals(actual.blocks, expected.blocks);
+ assertEquals(actual.ino, expected.ino);
+ assertEquals(actual.gid, expected.gid);
+ assertEquals(actual.mode, expected.mode);
+ assertEquals(actual.nlink, expected.nlink);
+ assertEquals(actual.rdev, expected.rdev);
+ assertEquals(actual.uid, expected.uid);
+ assertEquals(actual.atime?.getTime(), expected.atime?.getTime());
+ assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime());
+ assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime());
+ assertEquals(actual.atimeMs, expected.atime?.getTime());
+ assertEquals(actual.mtimeMs, expected.mtime?.getTime());
+ assertEquals(actual.birthtimeMs, expected.birthtime?.getTime());
+ assertEquals(actual.isFile(), expected.isFile);
+ assertEquals(actual.isDirectory(), expected.isDirectory);
+ assertEquals(actual.isSymbolicLink(), expected.isSymlink);
+ // assertEquals(actual.ctimeMs === expected.ctime?.getTime());
+ // assertEquals(actual.ctime?.getTime() === expected.ctime?.getTime());
+}
+
+export function assertStatsBigInt(
+ actual: BigIntStats,
+ expected: Deno.FileInfo,
+) {
+ assertEquals(actual.dev, BigInt(expected.dev));
+ assertEquals(actual.gid, BigInt(expected.gid));
+ assertEquals(actual.size, BigInt(expected.size));
+ assertEquals(actual.blksize, BigInt(expected.blksize));
+ assertEquals(actual.blocks, BigInt(expected.blocks));
+ assertEquals(actual.ino, BigInt(expected.ino));
+ assertEquals(actual.gid, BigInt(expected.gid));
+ assertEquals(actual.mode, BigInt(expected.mode));
+ assertEquals(actual.nlink, BigInt(expected.nlink));
+ assertEquals(actual.rdev, BigInt(expected.rdev));
+ assertEquals(actual.uid, BigInt(expected.uid));
+ assertEquals(actual.atime?.getTime(), expected.atime?.getTime());
+ assertEquals(actual.mtime?.getTime(), expected.mtime?.getTime());
+ assertEquals(actual.birthtime?.getTime(), expected.birthtime?.getTime());
+ assertEquals(Number(actual.atimeMs), expected.atime?.getTime());
+ assertEquals(Number(actual.mtimeMs), expected.mtime?.getTime());
+ assertEquals(Number(actual.birthtimeMs), expected.birthtime?.getTime());
+ assertEquals(Number(actual.atimeNs) / 1e6, expected.atime?.getTime());
+ assertEquals(Number(actual.mtimeNs) / 1e6, expected.atime?.getTime());
+ assertEquals(Number(actual.birthtimeNs) / 1e6, expected.atime?.getTime());
+ assertEquals(actual.isFile(), expected.isFile);
+ assertEquals(actual.isDirectory(), expected.isDirectory);
+ assertEquals(actual.isSymbolicLink(), expected.isSymlink);
+ // assertEquals(actual.ctime?.getTime() === expected.ctime?.getTime());
+ // assertEquals(Number(actual.ctimeMs) === expected.ctime?.getTime());
+ // assertEquals(Number(actual.ctimeNs) / 1e+6 === expected.ctime?.getTime());
+}
+
+Deno.test({
+ name: "ASYNC: get a file Stats",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ await new Promise<Stats>((resolve, reject) => {
+ stat(file, (err, stat) => {
+ if (err) reject(err);
+ resolve(stat);
+ });
+ })
+ .then((stat) => assertStats(stat, Deno.statSync(file)))
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(file));
+ },
+});
+
+Deno.test({
+ name: "SYNC: get a file Stats",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertStats(statSync(file), Deno.statSync(file));
+ },
+});
+
+Deno.test({
+ name: "ASYNC: get a file BigInt Stats",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ await new Promise<BigIntStats>((resolve, reject) => {
+ stat(file, { bigint: true }, (err, stat) => {
+ if (err) reject(err);
+ resolve(stat);
+ });
+ })
+ .then((stat) => assertStatsBigInt(stat, Deno.statSync(file)))
+ .catch(() => fail())
+ .finally(() => Deno.removeSync(file));
+ },
+});
+
+Deno.test({
+ name: "SYNC: get a file BigInt Stats",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ assertStatsBigInt(statSync(file, { bigint: true }), Deno.statSync(file));
+ },
+});
diff --git a/std/node/_fs/_fs_unlink.ts b/std/node/_fs/_fs_unlink.ts
new file mode 100644
index 000000000..aba734fe1
--- /dev/null
+++ b/std/node/_fs/_fs_unlink.ts
@@ -0,0 +1,10 @@
+export function unlink(path: string | URL, callback: (err?: Error) => void) {
+ if (!callback) throw new Error("No callback function supplied");
+ Deno.remove(path)
+ .then((_) => callback())
+ .catch(callback);
+}
+
+export function unlinkSync(path: string | URL) {
+ Deno.removeSync(path);
+}
diff --git a/std/node/_fs/_fs_unlink_test.ts b/std/node/_fs/_fs_unlink_test.ts
new file mode 100644
index 000000000..922a1a703
--- /dev/null
+++ b/std/node/_fs/_fs_unlink_test.ts
@@ -0,0 +1,30 @@
+import { assertEquals, fail } from "../../testing/asserts.ts";
+import { existsSync } from "../../fs/mod.ts";
+import { unlink, unlinkSync } from "./_fs_unlink.ts";
+
+Deno.test({
+ name: "ASYNC: deleting a file",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ await new Promise((resolve, reject) => {
+ unlink(file, (err) => {
+ if (err) reject(err);
+ resolve();
+ });
+ })
+ .then(() => assertEquals(existsSync(file), false))
+ .catch(() => fail())
+ .finally(() => {
+ if (existsSync(file)) Deno.removeSync(file);
+ });
+ },
+});
+
+Deno.test({
+ name: "SYNC: Test deleting a file",
+ fn() {
+ const file = Deno.makeTempFileSync();
+ unlinkSync(file);
+ assertEquals(existsSync(file), false);
+ },
+});
diff --git a/std/node/_fs/_fs_watch.ts b/std/node/_fs/_fs_watch.ts
new file mode 100644
index 000000000..a5f3bb9c1
--- /dev/null
+++ b/std/node/_fs/_fs_watch.ts
@@ -0,0 +1,111 @@
+import { fromFileUrl } from "../path.ts";
+import { EventEmitter } from "../events.ts";
+import { notImplemented } from "../_utils.ts";
+
+export function asyncIterableIteratorToCallback<T>(
+ iterator: AsyncIterableIterator<T>,
+ callback: (val: T, done?: boolean) => void,
+) {
+ function next() {
+ iterator.next().then((obj) => {
+ if (obj.done) {
+ callback(obj.value, true);
+ return;
+ }
+ callback(obj.value);
+ next();
+ });
+ }
+ next();
+}
+
+export function asyncIterableToCallback<T>(
+ iter: AsyncIterable<T>,
+ callback: (val: T, done?: boolean) => void,
+) {
+ const iterator = iter[Symbol.asyncIterator]();
+ function next() {
+ iterator.next().then((obj) => {
+ if (obj.done) {
+ callback(obj.value, true);
+ return;
+ }
+ callback(obj.value);
+ next();
+ });
+ }
+ next();
+}
+
+type watchOptions = {
+ persistent?: boolean;
+ recursive?: boolean;
+ encoding?: string;
+};
+
+type watchListener = (eventType: string, filename: string) => void;
+
+export function watch(
+ filename: string | URL,
+ options: watchOptions,
+ listener: watchListener,
+): FSWatcher;
+export function watch(
+ filename: string | URL,
+ listener: watchListener,
+): FSWatcher;
+export function watch(
+ filename: string | URL,
+ options: watchOptions,
+): FSWatcher;
+export function watch(filename: string | URL): FSWatcher;
+export function watch(
+ filename: string | URL,
+ optionsOrListener?: watchOptions | watchListener,
+ optionsOrListener2?: watchOptions | watchListener,
+) {
+ const listener = typeof optionsOrListener === "function"
+ ? optionsOrListener
+ : typeof optionsOrListener2 === "function"
+ ? optionsOrListener2
+ : undefined;
+ const options = typeof optionsOrListener === "object"
+ ? optionsOrListener
+ : typeof optionsOrListener2 === "object"
+ ? optionsOrListener2
+ : undefined;
+ filename = filename instanceof URL ? fromFileUrl(filename) : filename;
+
+ const iterator = Deno.watchFs(filename, {
+ recursive: options?.recursive || false,
+ });
+
+ if (!listener) throw new Error("No callback function supplied");
+
+ const fsWatcher = new FSWatcher(() => {
+ if (iterator.return) iterator.return();
+ });
+
+ fsWatcher.on("change", listener);
+
+ asyncIterableIteratorToCallback<Deno.FsEvent>(iterator, (val, done) => {
+ if (done) return;
+ fsWatcher.emit("change", val.kind, val.paths[0]);
+ });
+
+ return fsWatcher;
+}
+
+class FSWatcher extends EventEmitter {
+ close: () => void;
+ constructor(closer: () => void) {
+ super();
+ this.close = closer;
+ }
+ ref() {
+ notImplemented("FSWatcher.ref() is not implemented");
+ }
+ unref() {
+ notImplemented("FSWatcher.unref() is not implemented");
+ }
+}
diff --git a/std/node/_fs/_fs_watch_test.ts b/std/node/_fs/_fs_watch_test.ts
new file mode 100644
index 000000000..d8ea84be1
--- /dev/null
+++ b/std/node/_fs/_fs_watch_test.ts
@@ -0,0 +1,29 @@
+import { watch } from "./_fs_watch.ts";
+import { assertEquals } from "../../testing/asserts.ts";
+
+function wait(time: number) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time);
+ });
+}
+
+Deno.test({
+ name: "watching a file",
+ async fn() {
+ const file = Deno.makeTempFileSync();
+ const result: Array<[string, string]> = [];
+ const watcher = watch(
+ file,
+ (eventType, filename) => result.push([eventType, filename]),
+ );
+ await wait(100);
+ Deno.writeTextFileSync(file, "something");
+ await wait(100);
+ watcher.close();
+ assertEquals(result, [
+ ["modify", file],
+ ["modify", file],
+ ["access", file],
+ ]);
+ },
+});
diff --git a/std/node/fs.ts b/std/node/fs.ts
index adb3a7c63..fd8989c5b 100644
--- a/std/node/fs.ts
+++ b/std/node/fs.ts
@@ -11,6 +11,15 @@ 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, writeFileSync } from "./_fs/_fs_writeFile.ts";
+import { readdir, readdirSync } from "./_fs/_fs_readdir.ts";
+import { rename, renameSync } from "./_fs/_fs_rename.ts";
+import { rmdir, rmdirSync } from "./_fs/_fs_rmdir.ts";
+import { unlink, unlinkSync } from "./_fs/_fs_unlink.ts";
+import { watch } from "./_fs/_fs_watch.ts";
+import { open, openSync } from "./_fs/_fs_open.ts";
+import { stat, statSync } from "./_fs/_fs_stat.ts";
+import { lstat, lstatSync } from "./_fs/_fs_lstat.ts";
+
import * as promises from "./_fs/promises/mod.ts";
export {
@@ -29,13 +38,29 @@ export {
copyFileSync,
exists,
existsSync,
+ // not sure about those
+ lstat,
+ lstatSync,
mkdir,
mkdirSync,
+ open,
+ openSync,
promises,
+ readdir,
+ readdirSync,
readFile,
readFileSync,
readlink,
readlinkSync,
+ rename,
+ renameSync,
+ rmdir,
+ rmdirSync,
+ stat,
+ statSync,
+ unlink,
+ unlinkSync,
+ watch,
writeFile,
writeFileSync,
};