From 0fae176125857b9bb1fad4a14392fe442f8abdc9 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 12 Jul 2023 16:59:02 +0800 Subject: [PATCH] refactor: switch to native fs.promises --- src/fs.ts | 82 ++++++++++-------------------------------------------- test/fs.ts | 20 +++++++++++-- 2 files changed, 32 insertions(+), 70 deletions(-) diff --git a/src/fs.ts b/src/fs.ts index fe2a52ad..1db50538 100644 --- a/src/fs.ts +++ b/src/fs.ts @@ -15,76 +15,22 @@ export { } from 'fs' import { readdirSync as rdSync } from 'fs' -export const readdirSync = (path: fs.PathLike): Dirent[] => - rdSync(path, { withFileTypes: true }) - -// unrolled for better inlining, this seems to get better performance -// than something like: -// const makeCb = (res, rej) => (er, ...d) => er ? rej(er) : res(...d) -// which would be a bit cleaner. - -const chmod = (path: fs.PathLike, mode: fs.Mode): Promise => - new Promise((res, rej) => - fs.chmod(path, mode, (er, ...d: any[]) => (er ? rej(er) : res(...d))) - ) - -const mkdir = ( - path: fs.PathLike, - options?: - | fs.Mode - | (fs.MakeDirectoryOptions & { recursive?: boolean | null }) - | undefined - | null -): Promise => - new Promise((res, rej) => - fs.mkdir(path, options, (er, made) => (er ? rej(er) : res(made))) - ) - -const readdir = (path: fs.PathLike): Promise => - new Promise((res, rej) => - fs.readdir(path, { withFileTypes: true }, (er, data) => - er ? rej(er) : res(data) - ) - ) -const rename = (oldPath: fs.PathLike, newPath: fs.PathLike): Promise => - new Promise((res, rej) => - fs.rename(oldPath, newPath, (er, ...d: any[]) => (er ? rej(er) : res(...d))) - ) +import fsPromises from 'fs/promises' -const rm = (path: fs.PathLike, options: fs.RmOptions): Promise => - new Promise((res, rej) => - fs.rm(path, options, (er, ...d: any[]) => (er ? rej(er) : res(...d))) - ) - -const rmdir = (path: fs.PathLike): Promise => - new Promise((res, rej) => - fs.rmdir(path, (er, ...d: any[]) => (er ? rej(er) : res(...d))) - ) - -const stat = (path: fs.PathLike): Promise => - new Promise((res, rej) => - fs.stat(path, (er, data) => (er ? rej(er) : res(data))) - ) - -const lstat = (path: fs.PathLike): Promise => - new Promise((res, rej) => - fs.lstat(path, (er, data) => (er ? rej(er) : res(data))) - ) - -const unlink = (path: fs.PathLike): Promise => - new Promise((res, rej) => - fs.unlink(path, (er, ...d: any[]) => (er ? rej(er) : res(...d))) - ) +export const readdirSync = (path: fs.PathLike): Dirent[] => + rdSync(path, { withFileTypes: true }) export const promises = { - chmod, - mkdir, - readdir, - rename, - rm, - rmdir, - stat, - lstat, - unlink, + chmod: fsPromises.chmod, + mkdir: fsPromises.mkdir, + readdir(path: fs.PathLike) { + return fsPromises.readdir(path, { withFileTypes: true }) + }, + rename: fsPromises.rename, + rm: fsPromises.rm, + rmdir: fsPromises.rmdir, + stat: fsPromises.stat, + lstat: fsPromises.lstat, + unlink: fsPromises.unlink, } diff --git a/test/fs.ts b/test/fs.ts index 8d9cd0fb..7e5ddc42 100644 --- a/test/fs.ts +++ b/test/fs.ts @@ -13,17 +13,30 @@ const mockFSMethodPass = const cb = args.pop() process.nextTick(() => cb(null, method, 1, 2, 3)) } +const mockFSPromiseMethodPass = + (method: string) => + () => new Promise((resolve, reject) => { + resolve(method) + }) const mockFSMethodFail = (method: string) => (...args: any[]) => { const cb = args.pop() process.nextTick(() => cb(new Error('oops'), method, 1, 2, 3)) } +const mockFSPromiseMethodFail = + (method: string) => + () => new Promise((resolve, reject) => { + reject(new Error('oops')) + }) import { useNative } from '../dist/cjs/src/use-native.js' t.type(fs.promises, Object) const mockFSPass: { [k: string]: (...a: any[]) => any } = {} const mockFSFail: { [k: string]: (...a: any[]) => any } = {} +const mockFSPromisesPass: { [k: string]: (...a: any[]) => Promise } = {} +const mockFSPromisesFail: { [k: string]: (...a: any[]) => Promise } = {} + for (const method of Object.keys( fs.promises as { [k: string]: (...a: any[]) => any } )) { @@ -48,7 +61,9 @@ for (const method of Object.keys( // set up our pass/fails for the next tests mockFSPass[method] = mockFSMethodPass(method) + mockFSPromisesPass[method] = mockFSPromiseMethodPass(method) mockFSFail[method] = mockFSMethodFail(method) + mockFSPromisesFail[method] = mockFSPromiseMethodFail(method) } // doesn't have any sync versions that aren't promisified @@ -65,7 +80,7 @@ for (const method of Object.keys(fs)) { } t.test('passing resolves promise', async t => { - const fs = t.mock('../src/fs', { fs: mockFSPass }) + const fs = t.mock('../src/fs', { fs: mockFSPass, 'fs/promises': mockFSPromisesPass }) for (const [m, fn] of Object.entries( fs.promises as { [k: string]: (...a: any) => Promise } )) { @@ -74,7 +89,8 @@ t.test('passing resolves promise', async t => { }) t.test('failing rejects promise', async t => { - const fs = t.mock('../src/fs', { fs: mockFSFail }) + const fs = t.mock('../src/fs', { fs: mockFSFail, 'fs/promises': mockFSPromisesFail }) + for (const [m, fn] of Object.entries( fs.promises as { [k: string]: (...a: any[]) => Promise } )) {