UNPKG

@localnerve/gulp-responsive

Version:
149 lines (128 loc) 3.78 kB
import { Transform } from 'node:stream' import chalk from 'chalk' import flog from 'fancy-log' import { minimatch } from 'minimatch' import PluginError from 'plugin-error' import sharpVinyl from './sharp.js' import prepareConfig from './config.js' import { parsePackageJson } from './pkg.js' export default function gulpResponsive (config, options) { const statistics = { total: 0, matched: 0, created: 0, unmatched: 0, unmatchedBlocked: 0, unmatchedPassed: 0 } options = { errorOnUnusedConfig: true, errorOnUnusedImage: true, errorOnEnlargement: true, passThroughUnused: false, silent: false, stats: true, ...options } config = prepareConfig(config || [], options) async function getPluginName () { const packageJsonData = await parsePackageJson() return packageJsonData.name } async function transform (file, enc, done) { const PLUGIN_NAME = await getPluginName() const that = this if (file.isNull()) { this.push(file) return done() } if (file.isStream()) { return done(new PluginError(PLUGIN_NAME, 'Streaming not supported')) } statistics.total++ const matched = config.filter(conf => minimatch(file.relative, conf.name)) if (matched.length === 0) { statistics.unmatched++ const message = `File \`${file.relative}\`: Image does not match any config` if (options.errorOnUnusedImage) { return done(new PluginError(PLUGIN_NAME, message)) } else if (options.passThroughUnused) { this.push(file) statistics.unmatchedPassed++ if (!options.silent) { flog( PLUGIN_NAME + ': (pass through without changes)', chalk.magenta(message) ) } return done() } statistics.unmatchedBlocked++ if (!options.silent) { flog(PLUGIN_NAME + ': (skip for processing)', chalk.magenta(message)) } return done() } statistics.matched++ const allPromises = [] for (const conf of matched) { // config item matched (can be matched multiple times) conf.matched = true allPromises.push(sharpVinyl(file, conf, options)) } try { const result = await Promise.all(allPromises) result.forEach(newFiles => { if (newFiles) { newFiles.forEach(f => that.push(f)) statistics.created += newFiles.length } }) done() } catch (error) { done(new PluginError(PLUGIN_NAME, error, { showStack: true })) } } async function flush (cb) { const PLUGIN_NAME = await getPluginName() const notMatched = config.filter((conf) => !conf.matched) if (options.stats && !(options.silent && statistics.created === 0)) { const msg = 'Created ' + statistics.created + ' ' + statistics.created === 1 ? 'image' : 'images' + chalk.dim.white( ' (matched ' + statistics.matched + ' of ' + statistics.total + ' ' + statistics.total === 1 ? 'image' : 'images' + ')' ) flog(PLUGIN_NAME + ':', chalk.green(msg)) } if ( notMatched.length > 0 && (!options.silent || options.errorOnUnusedConfig) ) { let message = 'Available images do not match the following config:' notMatched.forEach(function (conf) { message += '\n - `' + conf.name + '`' }) if (options.errorOnUnusedConfig) { return cb(new PluginError(PLUGIN_NAME, message)) } else { flog(PLUGIN_NAME + ':', chalk.magenta(message)) } } cb() } return new Transform({ objectMode: true, transform, flush }) }