-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnuke.ts
More file actions
140 lines (113 loc) · 3.39 KB
/
nuke.ts
File metadata and controls
140 lines (113 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env bun
import type { Dirent } from "node:fs"
import {
readdir,
type readdir as readdirType,
rm,
type rm as rmType,
} from "node:fs/promises"
import { join, relative } from "node:path"
export const directoriesToNuke = new Set(["node_modules", "dist", "coverage"])
export type FsOperations = {
readdir: typeof readdirType
rm: typeof rmType
}
const defaultFs: FsOperations = { readdir, rm }
export async function scanDirectory(
dir: string,
fs: Pick<FsOperations, "readdir"> = defaultFs
): Promise<{ targets: string[]; subdirs: string[] }> {
const targets: string[] = []
const subdirs: string[] = []
const entries = await fs
.readdir(dir, { withFileTypes: true })
.catch(() => [] as Dirent[])
for (const entry of entries) {
if (entry.isDirectory()) {
const fullPath = join(dir, entry.name)
if (directoriesToNuke.has(entry.name)) {
targets.push(fullPath)
} else if (!entry.name.startsWith(".")) {
subdirs.push(fullPath)
}
}
}
return { targets, subdirs }
}
/**
* Recursively find all directories to nuke
* @param root - The root directory to start from
* @returns A list of directories to nuke
*/
export async function findAllTargets(
root: string,
fs: Pick<FsOperations, "readdir"> = defaultFs
): Promise<string[]> {
const allTargets: string[] = []
const processLevel = async (dirs: string[]): Promise<void> => {
if (dirs.length === 0) {
return
}
const results = await Promise.all(dirs.map((d) => scanDirectory(d, fs)))
const nextDirs: string[] = []
for (const { targets, subdirs } of results) {
allTargets.push(...targets)
nextDirs.push(...subdirs)
}
return processLevel(nextDirs)
}
await processLevel([root])
return allTargets
}
/**
* Find all .gen.ts files in packages/examples directory
* @param root - The root directory to start from
* @returns A list of generated file paths
*/
export async function findGeneratedFiles(root: string): Promise<string[]> {
const generatedFiles: string[] = []
const examplesDir = join(root, "packages", "examples")
const walkDir = async (dir: string): Promise<void> => {
const entries = await readdir(dir, { withFileTypes: true }).catch(
() => [] as Dirent[]
)
for (const entry of entries) {
const fullPath = join(dir, entry.name)
if (entry.isDirectory()) {
await walkDir(fullPath)
} else if (entry.isFile() && entry.name.endsWith(".gen.ts")) {
generatedFiles.push(fullPath)
}
}
}
await walkDir(examplesDir).catch(() => {
// Ignore errors - directory might not exist
})
return generatedFiles
}
export async function main(fs: FsOperations = defaultFs) {
const [dirTargets, fileTargets] = await Promise.all([
findAllTargets(".", fs),
findGeneratedFiles("."),
])
const allTargets = [...dirTargets, ...fileTargets]
if (allTargets.length === 0) {
console.log("Nothing to remove!")
return
}
console.log(`Deleting ${allTargets.length} items...`)
await Promise.all(
allTargets.map(async (target) => {
try {
await fs.rm(target, { recursive: true, force: true })
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
process.stdout.write(` Failed: ${target} - ${message}\n`)
}
})
)
console.log("Cleanup complete!")
}
if (import.meta.main) {
await main()
}