UNPKG

@rollup-extras/plugin-copy

Version:
174 lines (170 loc) 6.99 kB
'use strict'; var fs = require('fs/promises'); var fs_ = require('fs'); var path = require('path'); var glob = require('glob'); var globParent = require('glob-parent'); var options = require('@rollup-extras/utils/options'); var logger = require('@rollup-extras/utils/logger'); var statistics = require('@rollup-extras/utils/statistics'); const factories = { targets, logger }; const listFilenames = 'list-filenames'; function index (options$1) { const files = new Map(); const normalizedOptions = options.getOptions(options$1, { pluginName: '@rollup-extras/plugin-copy', copyOnce: true, flatten: false, verbose: false, exactFileNames: true, watch: true, emitFiles: true, outputPlugin: false, emitOriginalFileName: 'absolute' }, 'targets', factories); const { pluginName, copyOnce, verbose, exactFileNames, targets, outputPlugin, flatten, emitFiles, logger, emitOriginalFileName } = normalizedOptions; let { watch } = normalizedOptions; const hookName = outputPlugin ? 'generateBundle' : emitFiles ? 'buildStart' : 'buildEnd'; if (!outputPlugin && !emitFiles && watch) { watch = false; logger('can\'t use watch with emitFiles = false and outputPlugin = false', 0 /* LogLevel.verbose */); } if (outputPlugin && watch) { watch = false; logger('can\'t use watch with outputPlugin = true', 0 /* LogLevel.verbose */); } return { name: pluginName, async [hookName]() { const results = await Promise.all(targets .flatMap(target => Array.isArray(target.src) ? target.src.map(itemSrc => ({ ...target, src: itemSrc })) : target) .map(target => glob.glob(target.src, { ignore: target.exclude }) .then(result => ({ src: result, dest: target.dest ? target.dest : '', parent: globParent(target.src) })))); for (const result of results) { for (const file of result.src) { let fileDesc; if (files.has(file)) { fileDesc = files.get(file); } else { fileDesc = { dest: [], copied: [], timestamp: 0 }; files.set(file, fileDesc); } const dest = flatten ? normalizeSlash(result.dest) : path.join(result.dest, path.relative(result.parent, path.dirname(file))); if (!fileDesc.dest.includes(dest)) { fileDesc.dest.push(dest); } // don't forget to watch it if (watch) { this.addWatchFile(file); } } } const statisticsCollector = statistics(verbose === listFilenames, (result) => `copied ${typeof result == 'number' ? result + ' files' : result.join(', ')}`); logger.start('copying files', verbose ? 1 /* LogLevel.info */ : 0 /* LogLevel.verbose */); await Promise.all([...files].map(async ([fileName, fileDesc]) => { let source; try { const fileStat = await fs.stat(fileName); if (!fileStat.isFile()) { return; } const timestamp = fileStat.mtime.getTime(); if (timestamp > fileDesc.timestamp) { fileDesc.timestamp = timestamp; fileDesc.copied = []; } if (emitFiles) { source = await fs.readFile(fileName); } } catch (e) { const loglevel = e['code'] === 'ENOENT' ? undefined : 2 /* LogLevel.warn */; logger(`error reading file ${fileName}`, loglevel, e); return; } for (const dest of fileDesc.dest) { if (copyOnce && fileDesc.copied.includes(dest)) { continue; } const baseName = path.basename(fileName); // path.join removes ./ from the beginning, that's needed for rollup name/fileName fields const destFileName = path.join(dest, baseName); try { if (emitFiles) { this.emitFile({ type: 'asset', [exactFileNames ? 'fileName' : 'name']: destFileName, source: source, originalFileName: getOriginalFileName(fileName, emitOriginalFileName) }); } else { await fs.mkdir(path.dirname(destFileName), { recursive: true }); await fs.copyFile(fileName, destFileName, fs_.constants.COPYFILE_FICLONE); } if (verbose === listFilenames) { logger(`\t${fileName}${destFileName}`, 1 /* LogLevel.info */); } statisticsCollector(baseName); fileDesc.copied.push(dest); } catch (e) { logger(`error copying file ${fileName}${destFileName}`, 2 /* LogLevel.warn */, e); } } })); logger.finish(statisticsCollector()); } }; } function normalizeSlash(dir) { if (dir.endsWith('/')) { return `${dir.substring(0, dir.length - 1)}`; } return dir; } function targets(options, field) { let targets = options[field]; if (targets == null) { targets = [options]; } if (Array.isArray(targets)) { targets = targets.map((item) => { if (item) { if (typeof item === 'string') { return { src: item }; } if (typeof item === 'object' && 'src' in item) { return item; } } return undefined; }).filter(Boolean); } return targets; } function getOriginalFileName(fileName, emitOriginalFileName) { if (emitOriginalFileName === 'relative') { return fileName; } if (emitOriginalFileName === 'absolute') { return path.resolve(fileName); } if (typeof emitOriginalFileName === 'function') { return emitOriginalFileName(fileName); } return undefined; } module.exports = index;