@calmdown/rolldown-plugin-delete 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +129 -0
- package/package.json +14 -0
package/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const PLUGIN_NAME = "Delete";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} DeletePluginTarget
|
|
8
|
+
* @property {string|string[]} include glob pattern(s) of files to include
|
|
9
|
+
* @property {string|string[]} [exclude] glob pattern(s) to exclude (optional)
|
|
10
|
+
* @property {"before"|"after"} [trigger="before"] when to run the operation (defaults to "before")
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} DeletePluginOptions
|
|
15
|
+
* @property {(string|DeletePluginTarget)|(string|DeletePluginTarget)[]} targets desired delete operations
|
|
16
|
+
* @property {boolean} [dryRun=false] whether to perform a dry run, only logging actions without executing them (defaults to false)
|
|
17
|
+
* @property {boolean} [runOnce=true] when in watch mode, controls whether to only delete files on the first build (defaults to true)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {DeletePluginOptions} pluginOptions
|
|
22
|
+
*/
|
|
23
|
+
export default function DeletePlugin(pluginOptions) {
|
|
24
|
+
const targets = toArray(pluginOptions?.targets ?? []).map(it => typeof it === "string" ? { include: it } : it);
|
|
25
|
+
|
|
26
|
+
const exec = (context, message, block) => {
|
|
27
|
+
if (pluginOptions?.dryRun) {
|
|
28
|
+
message && context.info({
|
|
29
|
+
plugin: PLUGIN_NAME,
|
|
30
|
+
pluginCode: "DRY_RUN",
|
|
31
|
+
message,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return block();
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const execTarget = async (context, cwd, target) => {
|
|
41
|
+
const include = toArray(target.include);
|
|
42
|
+
const globOptions = {
|
|
43
|
+
cwd,
|
|
44
|
+
exclude: toArray(target.exclude ?? []),
|
|
45
|
+
withFileTypes: true,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const includePattern of include) {
|
|
50
|
+
for await (const entry of fs.glob(includePattern, globOptions)) {
|
|
51
|
+
entries.push(entry);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
entries.sort(directoriesLast);
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const entryPath = path.join(entry.parentPath, entry.name);
|
|
58
|
+
if (entry.isFile()) {
|
|
59
|
+
await exec(context, `would delete file ${entryPath}`, () => fs.unlink(entryPath));
|
|
60
|
+
}
|
|
61
|
+
else if (entry.isSymbolicLink()) {
|
|
62
|
+
await exec(context, `would delete symlink ${entryPath}`, () => fs.unlink(entryPath));
|
|
63
|
+
}
|
|
64
|
+
else if (entry.isDirectory()) {
|
|
65
|
+
try {
|
|
66
|
+
await exec(context, `would delete directory ${entryPath}`, () => fs.rmdir(entryPath));
|
|
67
|
+
}
|
|
68
|
+
catch (ex) {
|
|
69
|
+
// ignore errors when directory is not empty
|
|
70
|
+
if (ex?.code !== "ENOTEMPTY") {
|
|
71
|
+
throw ex;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
let cwd = undefined;
|
|
79
|
+
let isFirstBeforeRun = true;
|
|
80
|
+
let isFirstAfterRun = true;
|
|
81
|
+
return {
|
|
82
|
+
name: PLUGIN_NAME,
|
|
83
|
+
async buildStart() {
|
|
84
|
+
if (pluginOptions?.runOnce !== false && !isFirstBeforeRun) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
isFirstBeforeRun = false;
|
|
89
|
+
cwd = process.cwd();
|
|
90
|
+
for (const target of targets) {
|
|
91
|
+
const { trigger } = target;
|
|
92
|
+
if (trigger === "before" || trigger === undefined) {
|
|
93
|
+
await execTarget(this, cwd, target);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
async closeBundle() {
|
|
98
|
+
if (pluginOptions?.runOnce !== false && !isFirstAfterRun) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
isFirstAfterRun = false;
|
|
103
|
+
for (const target of targets) {
|
|
104
|
+
if (target.trigger === "after") {
|
|
105
|
+
await execTarget(this, cwd, target);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function toArray(oneOrMore) {
|
|
113
|
+
return Array.isArray(oneOrMore) ? oneOrMore : [ oneOrMore ];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function directoriesLast(a, b) {
|
|
117
|
+
// delete files first
|
|
118
|
+
if (a.isDirectory()) {
|
|
119
|
+
if (!b.isDirectory()) {
|
|
120
|
+
return 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (b.isDirectory()) {
|
|
124
|
+
return -1;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// delete directories last, upwards
|
|
128
|
+
return b.parentPath.length - a.parentPath.length;
|
|
129
|
+
}
|