rsnext/packages/next/lib/recursive-delete.ts
JJ Kasper eb7b40171a
Add initial standalone build handling (#31003)
* Add initial standalone handling

* apply suggestions

* Apply suggestions from code review

Co-authored-by: Steven <steven@ceriously.com>
2021-11-09 11:03:20 -06:00

91 lines
2.2 KiB
TypeScript

import { Dirent, promises } from 'fs'
import { join, isAbsolute, dirname } from 'path'
import { promisify } from 'util'
import isError from './is-error'
const sleep = promisify(setTimeout)
const unlinkPath = async (p: string, isDir = false, t = 1): Promise<void> => {
try {
if (isDir) {
await promises.rmdir(p)
} else {
await promises.unlink(p)
}
} catch (e) {
const code = isError(e) && e.code
if (
(code === 'EBUSY' ||
code === 'ENOTEMPTY' ||
code === 'EPERM' ||
code === 'EMFILE') &&
t < 3
) {
await sleep(t * 100)
return unlinkPath(p, isDir, t++)
}
if (code === 'ENOENT') {
return
}
throw e
}
}
/**
* Recursively delete directory contents
* @param {string} dir Directory to delete the contents of
* @param {RegExp} [exclude] Exclude based on relative file path
* @param {string} [previousPath] Ensures that parameter dir exists, this is not passed recursively
* @returns Promise void
*/
export async function recursiveDelete(
dir: string,
exclude?: RegExp,
previousPath: string = ''
): Promise<void> {
let result
try {
result = await promises.readdir(dir, { withFileTypes: true })
} catch (e) {
if (isError(e) && e.code === 'ENOENT') {
return
}
throw e
}
await Promise.all(
result.map(async (part: Dirent) => {
const absolutePath = join(dir, part.name)
// readdir does not follow symbolic links
// if part is a symbolic link, follow it using stat
let isDirectory = part.isDirectory()
const isSymlink = part.isSymbolicLink()
if (isSymlink) {
const linkPath = await promises.readlink(absolutePath)
try {
const stats = await promises.stat(
isAbsolute(linkPath)
? linkPath
: join(dirname(absolutePath), linkPath)
)
isDirectory = stats.isDirectory()
} catch (_) {}
}
const pp = join(previousPath, part.name)
const isNotExcluded = !exclude || !exclude.test(pp)
if (isNotExcluded) {
if (isDirectory) {
await recursiveDelete(absolutePath, exclude, pp)
}
return unlinkPath(absolutePath, !isSymlink && isDirectory)
}
})
)
}