1 | import { pFilter, pMap, _since } from '@naturalcycles/js-lib'
|
2 | import * as fs from 'fs-extra'
|
3 | import { dimGrey, yellow } from '../colors'
|
4 | import { globby } from '../index'
|
5 |
|
6 | export interface DelOptions {
|
7 | |
8 |
|
9 |
|
10 | patterns: string[]
|
11 |
|
12 | |
13 |
|
14 |
|
15 | concurrency?: number
|
16 |
|
17 | verbose?: boolean
|
18 |
|
19 | silent?: boolean
|
20 |
|
21 | debug?: boolean
|
22 |
|
23 | dry?: boolean
|
24 | }
|
25 |
|
26 | export type DelSingleOption = string
|
27 |
|
28 | const DEF_OPT: DelOptions = {
|
29 | patterns: [],
|
30 | concurrency: Number.POSITIVE_INFINITY,
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | export async function del(_opt: DelOptions | DelSingleOption): Promise<void> {
|
39 | const started = Date.now()
|
40 |
|
41 |
|
42 | if (typeof _opt === 'string') {
|
43 | _opt = {
|
44 | patterns: [_opt],
|
45 | }
|
46 | }
|
47 |
|
48 | const opt = {
|
49 | ...DEF_OPT,
|
50 | ..._opt,
|
51 | concurrency: _opt.concurrency || DEF_OPT.concurrency,
|
52 | }
|
53 | const { patterns, concurrency, verbose, silent, debug, dry } = opt
|
54 |
|
55 | if (debug) {
|
56 | console.log(opt)
|
57 | }
|
58 |
|
59 |
|
60 |
|
61 | const filenames = await globby(patterns, {
|
62 | dot: true,
|
63 | expandDirectories: true,
|
64 | onlyFiles: true,
|
65 | })
|
66 |
|
67 | if (verbose || debug || dry) {
|
68 | console.log(`Will delete ${yellow(filenames.length)} files:`, filenames)
|
69 | }
|
70 |
|
71 | if (dry) return
|
72 |
|
73 | await pMap(filenames, filepath => fs.remove(filepath), { concurrency })
|
74 |
|
75 |
|
76 | let dirnames = await globby(patterns, {
|
77 | dot: true,
|
78 | expandDirectories: true,
|
79 | onlyDirectories: true,
|
80 | })
|
81 |
|
82 |
|
83 | dirnames = dirnames.concat(
|
84 | await pFilter(patterns, async pattern => {
|
85 | return (await fs.pathExists(pattern)) && (await fs.lstat(pattern)).isDirectory()
|
86 | }),
|
87 | )
|
88 |
|
89 | const dirnamesSorted = dirnames.sort().reverse()
|
90 |
|
91 |
|
92 |
|
93 | const deletedDirs: string[] = []
|
94 | for await (const dirpath of dirnamesSorted) {
|
95 | if (await isEmptyDir(dirpath)) {
|
96 |
|
97 | await fs.remove(dirpath)
|
98 | deletedDirs.push(dirpath)
|
99 | }
|
100 | }
|
101 |
|
102 | if (verbose || debug) console.log({ deletedDirs })
|
103 |
|
104 | if (!silent) {
|
105 | console.log(
|
106 | `del deleted ${yellow(filenames.length)} files and ${yellow(
|
107 | deletedDirs.length,
|
108 | )} dirs ${dimGrey(_since(started))}`,
|
109 | )
|
110 | }
|
111 | }
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 | async function isEmptyDir(dir: string): Promise<boolean> {
|
119 | return (await fs.readdir(dir)).length === 0
|
120 | }
|