UNPKG

@rollup-extras/plugin-clean

Version:
173 lines (149 loc) 5.03 kB
import { rm } from 'node:fs/promises'; import { dirname, normalize } from 'node:path'; import { createLogger, LogLevel } from '@niceties/logger'; import { multiConfigPluginBase } from '@rollup-extras/utils/multi-config-plugin-base'; import { getOptions } from '@rollup-extras/utils/options'; export default function (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 ( outputOptions, inputOptions ) { baseRenderStart.call(this, outputOptions, inputOptions); await renderStart(outputOptions); }; } else { instance.buildStart = buildStart; instance.options = optionsHook; } instance.api.addInstance = () => { const instance = baseAddInstance(); const baseRenderStart = ( (instance).renderStart ); if (outputPlugin) { instance.renderStart = async function ( outputOptions, inputOptions ) { baseRenderStart.call(this, outputOptions, inputOptions); await renderStart(outputOptions); }; } 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; } 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(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 { parentsInProgress = Array.from(parentDirs(dir)).filter(item => inProgress.has(item)); if (parentsInProgress.length > 0) { return inProgress.get( (parentsInProgress[0])); } 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 ? LogLevel.info : LogLevel.verbose); await rm(normalizedDir, { recursive: true }); logger.finish(`cleaned '${normalizedDir}'`); } catch ( e) { const loglevel = (e).code === 'ENOENT' ? undefined : 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) { for (;;) { dir = dirname(dir); if (dir === '.' || dir === '/') { break; } yield dir; } }