/**
* @file plugins/clean.js
* @copyright @spmhome @_2025
* @author Scott Meesseman @spmeesseman
*//** */
const { join } = require("path");
const WpwPlugin = require("../base");
const { readdir } = require("fs/promises");
const { existsSync, findFiles, rmDirIfEmpty, deleteFile, resolvePath } = require("@spmhome/cmn-utils");
/**
* @augments WpwPlugin
*/
class WpwCleanPlugin extends WpwPlugin
{
/**
* @param {WpwPluginOptions} options
*/
constructor(options)
{
super(options);
this.buildOptions = /** @type {WpwBuildOptionsPluginConfig<"clean">} */(this.buildOptions); // reset for typings
}
/**
* @override
* @static
*/
static create = WpwCleanPlugin.wrap.bind(this);
/**
* @override
* @returns {WpwPluginTapOptions<any, any, boolean> | undefined}
*/
onApply()
{
return { cleanBuildOutput: { async: true, hook: "beforeRun", callback: this.cleanBuild.bind(this) }};
}
/**
* @private
* @param {WebpackCompilation} _compilation
* @returns {Promise<void>}
*/
async cleanBuild(_compilation)
{
this.hookstart();
try
{ await this.cleanBuildAssets();
await this.cleanBuildCaches();
await rmDirIfEmpty(this.build.virtualEntry.dir);
this.build.createVirtualBuildPaths();
await this.cleanWebpackCache();
}
catch (e) {
this.addMessage({ message: "failed to execute all 'clean' tasks", exception: e }, true);
}
finally {
this.hookdone();
}
}
/**
* @private
* @returns {Promise<void>}
*/
async cleanBuildAssets()
{
const distPath = this.compiler.outputPath || this.compilation.outputOptions.path || this.build.getDistPath(),
compilerOptions = this.build.tsc.compilerOptions;
this.logger.write("clean build assets", 1);
await this.deleteDir("distribution", distPath, " ");
await this.deleteDir("v-dir build", this.build.virtualEntry.dirBuild, " ");
await this.deleteDir("v-dir distribution", this.build.virtualEntry.dirDist, " ");
if (!!compilerOptions.outDir && compilerOptions.outDir !== distPath)
{
await this.deleteDir("ts.outdir", resolvePath(this.build.source.info.dir, compilerOptions.outDir), " ");
}
}
/**
* @private
* @returns {Promise<void>}
*/
async cleanBuildCaches()
{
this.logger.write("clean wpw build cache", 1);
this.logger.write(" check for tsbuildinfo incremental file", 3);
const buildInfoFile = await findFiles("**/*.tsbuildinfo", { cwd: this.build.virtualEntry.dir })[0];
if (buildInfoFile)
{
this.logger.value(" delete tsbuildinfo file", buildInfoFile, 2);
await deleteFile(buildInfoFile);
}
if (existsSync(this.build.virtualEntry.dirStore))
{
await this.deleteDir("v-dir cache", this.build.virtualEntry.dirStore, " ");
}
}
/**
* @private
* @returns {Promise<void>}
*/
async cleanWebpackCache()
{
this.logger.write("clean webpack cache", 1);
const wpCacheDir = this.wpc.cache.type === "filesystem" ? this.wpc.cache.cacheDirectory : null;
if (wpCacheDir)
{
await this.deleteDir("webpack cache", wpCacheDir, " ");
}
else {
this.logger.write(" webpack cache is configured as 'memory' type, skip task", 1);
}
}
/**
* @private
* @param {string} dirType
* @param {string} dir
* @param {string} lPad
*/
async deleteDir(dirType, dir, lPad)
{
if (!!dir && existsSync(dir))
{
this.logger.value(`delete ${dirType} directory`, this.build.virtualEntry.dirDist, 2, lPad);
const files = (await readdir(dir)).filter((f) => this.isOutputAsset(f));
for (const file of files) {
this.build.logger.value(" delete file asset", file, 3, lPad);
await deleteFile(join(dir, file));
}
await rmDirIfEmpty(dir);
}
}
}
module.exports = WpwCleanPlugin.create;