UNPKG

2.62 kBJavaScriptView Raw
1import fs from 'node:fs';
2import fsPromises from 'node:fs/promises';
3import path from 'node:path';
4import process from 'node:process';
5import {globby, globbySync} from 'globby';
6import isGlob from 'is-glob';
7import isPathCwd from 'is-path-cwd';
8import isPathInside from 'is-path-inside';
9import pMap from 'p-map';
10import slash from 'slash';
11
12function safeCheck(file, cwd) {
13 if (isPathCwd(file)) {
14 throw new Error('Cannot delete the current working directory. Can be overridden with the `force` option.');
15 }
16
17 if (!isPathInside(file, cwd)) {
18 throw new Error('Cannot delete files/directories outside the current working directory. Can be overridden with the `force` option.');
19 }
20}
21
22function normalizePatterns(patterns) {
23 patterns = Array.isArray(patterns) ? patterns : [patterns];
24
25 patterns = patterns.map(pattern => {
26 if (process.platform === 'win32' && isGlob(pattern) === false) {
27 return slash(pattern);
28 }
29
30 return pattern;
31 });
32
33 return patterns;
34}
35
36export async function deleteAsync(patterns, {force, dryRun, cwd = process.cwd(), onProgress = () => {}, ...options} = {}) {
37 options = {
38 expandDirectories: false,
39 onlyFiles: false,
40 followSymbolicLinks: false,
41 cwd,
42 ...options,
43 };
44
45 patterns = normalizePatterns(patterns);
46
47 const paths = await globby(patterns, options);
48 const files = paths.sort((a, b) => b.localeCompare(a));
49
50 if (files.length === 0) {
51 onProgress({
52 totalCount: 0,
53 deletedCount: 0,
54 percent: 1,
55 });
56 }
57
58 let deletedCount = 0;
59
60 const mapper = async file => {
61 file = path.resolve(cwd, file);
62
63 if (!force) {
64 safeCheck(file, cwd);
65 }
66
67 if (!dryRun) {
68 await fsPromises.rm(file, {recursive: true, force: true});
69 }
70
71 deletedCount += 1;
72
73 onProgress({
74 totalCount: files.length,
75 deletedCount,
76 percent: deletedCount / files.length,
77 path: file,
78 });
79
80 return file;
81 };
82
83 const removedFiles = await pMap(files, mapper, options);
84
85 removedFiles.sort((a, b) => a.localeCompare(b));
86
87 return removedFiles;
88}
89
90export function deleteSync(patterns, {force, dryRun, cwd = process.cwd(), ...options} = {}) {
91 options = {
92 expandDirectories: false,
93 onlyFiles: false,
94 followSymbolicLinks: false,
95 cwd,
96 ...options,
97 };
98
99 patterns = normalizePatterns(patterns);
100
101 const files = globbySync(patterns, options)
102 .sort((a, b) => b.localeCompare(a));
103
104 const removedFiles = files.map(file => {
105 file = path.resolve(cwd, file);
106
107 if (!force) {
108 safeCheck(file, cwd);
109 }
110
111 if (!dryRun) {
112 fs.rmSync(file, {recursive: true, force: true});
113 }
114
115 return file;
116 });
117
118 removedFiles.sort((a, b) => a.localeCompare(b));
119
120 return removedFiles;
121}