@rollup-extras/plugin-clean
Version:
Rollup plugin to clean a directory during build.
135 lines (132 loc) • 4.7 kB
JavaScript
import fs from 'fs/promises';
import path from 'path';
import { createLogger } from '@niceties/logger';
import { getOptions } from '@rollup-extras/utils/options';
import { multiConfigPluginBase } from '@rollup-extras/utils/mutli-config-plugin-base';
function index (options = {}) {
const inProgress = new Map();
const hasChildrenInProgress = new Map();
let deleted = false;
const normalizedOptions = getOptions(options, {
pluginName: '@rollup-extras/plugin-clean',
deleteOnce: true,
verbose: false,
outputPlugin: true
}, 'targets');
const { pluginName, deleteOnce, verbose, outputPlugin } = normalizedOptions;
let { targets } = normalizedOptions;
const instance = multiConfigPluginBase(false, pluginName, cleanup);
const baseAddInstance = instance.api.addInstance;
const baseRenderStart = instance.renderStart;
if (outputPlugin) {
instance.renderStart = async function (options, inputOptions) {
baseRenderStart.call(this, options, inputOptions);
await renderStart(options);
};
}
else {
instance.buildStart = buildStart;
instance.options = optionsHook;
}
instance.api.addInstance = () => {
const instance = baseAddInstance();
const baseRenderStart = instance.renderStart;
if (outputPlugin) {
instance.renderStart = async function (options, inputOptions) {
baseRenderStart.call(this, options, inputOptions);
await renderStart(options);
};
}
else {
instance.buildStart = buildStart;
instance.options = optionsHook;
}
return instance;
};
return instance;
async function optionsHook(config) {
if (!targets && config) {
targets = (Array.isArray(config.output) ? config.output.map(item => item.dir) : [config.output?.dir])
.filter(Boolean);
}
return null;
}
async function buildStart() {
if (deleted) {
return;
}
if (targets) {
await Promise.all(targets.map(removeDir));
}
}
async function renderStart(options) {
if (deleted) {
return;
}
if (!targets) {
if (options.dir) {
await removeDir(options.dir);
}
}
else {
await Promise.all(targets.map(removeDir));
}
}
async function removeDir(dir) {
const normalizedDir = normalizeSlash(path.normalize(dir));
if (inProgress.has(normalizedDir)) {
return outputPlugin && inProgress.get(normalizedDir);
}
let removePromise;
let parentsInProgress;
if (hasChildrenInProgress.has(dir)) {
removePromise = Promise.resolve(hasChildrenInProgress.get(dir))
.then(() => doRemove(normalizedDir));
}
else if ((parentsInProgress = Array.from(parentDirs(dir)).filter(item => inProgress.has(item))).length > 0) {
return inProgress.get(parentsInProgress[0]);
}
else {
removePromise = doRemove(normalizedDir);
}
inProgress.set(normalizedDir, removePromise);
for (const parentDir of parentDirs(dir)) {
if (!hasChildrenInProgress.has(parentDir)) {
hasChildrenInProgress.set(parentDir, removePromise);
}
else {
hasChildrenInProgress.set(parentDir, Promise.all([removePromise, hasChildrenInProgress.get(parentDir)]));
}
}
return removePromise;
}
async function doRemove(normalizedDir) {
const logger = createLogger(pluginName);
try {
logger.start(`cleaning '${normalizedDir}'`, verbose ? 1 /* LogLevel.info */ : 0 /* LogLevel.verbose */);
await fs.rm(normalizedDir, { recursive: true });
logger.finish(`cleaned '${normalizedDir}'`);
}
catch (e) { // eslint-disable-line @typescript-eslint/no-explicit-any
const loglevel = e['code'] === 'ENOENT' ? undefined : 2 /* LogLevel.warn */;
logger.finish(`failed cleaning '${normalizedDir}'`, loglevel, e);
}
}
function cleanup() {
inProgress.clear();
hasChildrenInProgress.clear();
deleted = deleteOnce;
}
}
function normalizeSlash(dir) {
if (dir.endsWith('/')) {
return `${dir.substring(0, dir.length - 1)}`;
}
return dir;
}
function* parentDirs(dir) {
while (((dir = path.dirname(dir)) !== '.') && (dir !== '/')) {
yield dir;
}
}
export { index as default };