From 7e84718fd01b1035f891be30350f56777faae3dc Mon Sep 17 00:00:00 2001 From: jarvisjiang Date: Fri, 17 May 2024 15:49:30 +0800 Subject: [PATCH] add `fs.emptyDir` --- src/std/fs/mina_fs.ts | 89 ++++++++++++++++++++++++++++++++++--------- src/std/fs/mod.ts | 13 ++++++- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/std/fs/mina_fs.ts b/src/std/fs/mina_fs.ts index 7fbe861..7a7fd7a 100644 --- a/src/std/fs/mina_fs.ts +++ b/src/std/fs/mina_fs.ts @@ -1,6 +1,6 @@ import { basename, dirname } from '@std/path/posix'; import { NOT_FOUND_ERROR, assertAbsolutePath, type ExistsOptions, type WriteOptions } from 'happy-opfs'; -import { Err, Ok, type AsyncIOResult } from 'happy-rusty'; +import { Err, Ok, type AsyncIOResult, type IOResult } from 'happy-rusty'; import { assertSafeUrl, assertString } from '../assert/assertions.ts'; import type { FileEncoding, ReadFileContent, ReadOptions, WriteFileContent } from './fs_define.ts'; @@ -39,6 +39,23 @@ function getAbsolutePath(path: string): string { return rootPath + path; } +/** + * interface FileError 转换为 Err + * @param err FileError + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function toErr(err: WechatMinigame.FileError | WechatMinigame.GeneralCallbackResult): IOResult { + const error = new Error(err.errMsg); + + // 1300002 no such file or directory ${path} + // 可能没有errCode + if ((err as WechatMinigame.FileError).errCode === 1300002 || err.errMsg.includes('no such file or directory')) { + error.name = NOT_FOUND_ERROR; + } + + return Err(error); +} + /** * 递归创建文件夹,相当于`mkdir -p` * @param dirPath 要创建的文件夹路径 @@ -62,7 +79,7 @@ export function mkdir(dirPath: string): AsyncIOResult { return; } - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -83,7 +100,7 @@ export function readDir(dirPath: string): AsyncIOResult { resolve(Ok(res.files)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -120,7 +137,7 @@ export function readFile(filePath: string, options?: resolve(Ok(res.data as T)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -149,7 +166,7 @@ export async function remove(path: string): AsyncIOResult { resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); } else { @@ -159,7 +176,7 @@ export async function remove(path: string): AsyncIOResult { resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); } @@ -184,7 +201,7 @@ export function rename(oldPath: string, newPath: string): AsyncIOResult resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -205,15 +222,7 @@ export function stat(path: string): AsyncIOResult { resolve(Ok(res.stats as WechatMinigame.Stats)); }, fail(err): void { - const error = new Error(err.errMsg); - - // 1300002 no such file or directory ${path} - // 可能没有errCode - if (err.errCode === 1300002 || err.errMsg.includes('no such file or directory')) { - error.name = NOT_FOUND_ERROR; - } - - resolve(Err(error)); + resolve(toErr(err)); }, }); }); @@ -253,7 +262,7 @@ export async function writeFile(filePath: string, contents: WriteFileContent, op resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -300,6 +309,48 @@ export async function exists(path: string, options?: ExistsOptions): AsyncIOResu return Ok(!notExist); } +/** + * 清空文件夹,不存在则创建 + * @param dirPath 文件夹路径 + * @returns + */ +export async function emptyDir(dirPath: string): AsyncIOResult { + type T = boolean; + + const res = await readDir(dirPath); + if (res.isErr()) { + if (res.err().name === NOT_FOUND_ERROR) { + // 不存在则创建 + return mkdir(dirPath); + } + + return res; + } + + const items: AsyncIOResult[] = []; + + for await (const name of res.unwrap()) { + items.push(remove(`${ dirPath }/${ name }`)); + } + + const success: IOResult = await Promise.all(items).then((x) => { + let err: IOResult | null = null; + + const success = x.every(y => { + if (y.isErr()) { + err = y; + return false; + } + + return y.unwrap(); + }); + + return err ?? Ok(success); + }); + + return success; +} + /** * 以字符串格式读取文件 * @param filePath 要读取的文件路径 @@ -331,7 +382,7 @@ export function downloadFile(fileUrl: string, filePath: string, headers?: Header resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); @@ -358,7 +409,7 @@ export async function uploadFile(filePath: string, fileUrl: string, headers?: He resolve(Ok(true)); }, fail(err): void { - resolve(Err(new Error(err.errMsg))); + resolve(toErr(err)); }, }); }); diff --git a/src/std/fs/mod.ts b/src/std/fs/mod.ts index 77b1da0..62cbd1b 100644 --- a/src/std/fs/mod.ts +++ b/src/std/fs/mod.ts @@ -1,6 +1,7 @@ import { appendFile as webAppendFile, downloadFile as webDownloadFile, + emptyDir as webEmptyDir, exists as webExists, mkdir as webMkdir, readDir as webReadDir, @@ -18,6 +19,7 @@ import type { WriteFileContent } from './fs_define.ts'; import { appendFile as minaAppendFile, downloadFile as minaDownloadFile, + emptyDir as minaEmptyDir, exists as minaExists, mkdir as minaMkdir, readDir as minaReadDir, @@ -163,6 +165,15 @@ export function exists(path: string): AsyncIOResult { return isMinaEnv() ? minaExists(path) : webExists(path); } +/** + * 清空文件夹,不存在则创建 + * @param dirPath 文件夹路径 + * @returns + */ +export function emptyDir(dirPath: string): AsyncIOResult { + return isMinaEnv() ? minaEmptyDir(dirPath) : webEmptyDir(dirPath); +} + /** * 读取文件内容,返回`string` * @param filePath 要读取的文件路径 @@ -178,6 +189,6 @@ export function readTextFile(filePath: string): AsyncIOResult { * @param requestInit 传递给`fetch`的参数 * @returns */ -export async function uploadFile(filePath: string, fileUrl: string, requestInit?: RequestInit): AsyncIOResult { +export function uploadFile(filePath: string, fileUrl: string, requestInit?: RequestInit): AsyncIOResult { return isMinaEnv() ? minaUploadFile(filePath, fileUrl, requestInit?.headers) : webUploadFile(filePath, fileUrl, requestInit); }