UNPKG

@rollup-extras/plugin-clean

Version:
135 lines (132 loc) 4.7 kB
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 };