let hookTypes; const callStyles = { sync: 'applyPlugins', syncWaterfall: 'applyPluginsWaterfall', syncBail: 'applyPluginsBailResult', sync_map: 'applyPlugins', asyncWaterfall: 'applyPluginsAsyncWaterfall', asyncParallel: 'applyPluginsParallel', asyncSerial: 'applyPluginsAsync', }; const camelToDash = camel => camel.replace(/_/g, '--').replace(/[A-Z]/g, c => `-${c.toLowerCase()}`); const knownPluginRegistrations = { Compilation: { needAdditionalPass: ['sync', []], succeedModule: ['sync', ['module']], buildModule: ['sync', ['module']], seal: ['sync', []], }, Compiler: { afterCompile: ['asyncSerial', ['compilation']], afterEnvironment: ['sync', []], afterPlugins: ['sync', []], afterResolvers: ['sync', []], compilation: ['sync', ['compilation', 'params']], emit: ['asyncSerial', ['compilation']], make: ['asyncParallel', ['compilation']], watchRun: ['asyncSerial', ['watcher']], run: ['asyncSerial', ['compiler']], }, NormalModuleFactory: { createModule: ['syncBail', ['data']], parser: ['sync_map', ['parser', 'parserOptions']], resolver: ['syncWaterfall', ['nextResolver']], }, ContextModuleFactory: { afterResolve: ['asyncWaterfall', ['data']], }, }; exports.register = (tapable, name, style, args) => { if (tapable.hooks) { if (!hookTypes) { const Tapable = require('tapable'); hookTypes = { sync: Tapable.SyncHook, syncWaterfall: Tapable.SyncWaterfallHook, syncBail: Tapable.SyncBailHook, asyncWaterfall: Tapable.AsyncWaterfallHook, asyncParallel: Tapable.AsyncParallelHook, asyncSerial: Tapable.AsyncSeriesHook, asyncSeries: Tapable.AsyncSeriesHook, }; } if (!tapable.hooks[name]) { tapable.hooks[name] = new hookTypes[style](args); } } else { if (!tapable.__hardSource_hooks) { tapable.__hardSource_hooks = {}; } if (!tapable.__hardSource_hooks[name]) { tapable.__hardSource_hooks[name] = { name, dashName: camelToDash(name), style, args, async: style.startsWith('async'), map: style.endsWith('_map'), }; } if (!tapable.__hardSource_proxy) { tapable.__hardSource_proxy = {}; } if (!tapable.__hardSource_proxy[name]) { if (tapable.__hardSource_hooks[name].map) { const _forCache = {}; tapable.__hardSource_proxy[name] = { _forCache, for: key => { let hook = _forCache[key]; if (hook) { return hook; } _forCache[key] = { tap: (...args) => exports.tapFor(tapable, name, key, ...args), tapPromise: (...args) => exports.tapPromiseFor(tapable, name, key, ...args), call: (...args) => exports.callFor(tapable, name, key, ...args), promise: (...args) => exports.promiseFor(tapable, name, key, ...args), }; return _forCache[key]; }, tap: (...args) => exports.tapFor(tapable, name, ...args), tapPromise: (...args) => exports.tapPromiseFor(tapable, name, ...args), call: (...args) => exports.callFor(tapable, name, ...args), promise: (...args) => exports.promiseFor(tapable, name, ...args), }; } else { tapable.__hardSource_proxy[name] = { tap: (...args) => exports.tap(tapable, name, ...args), tapPromise: (...args) => exports.tapPromise(tapable, name, ...args), call: (...args) => exports.call(tapable, name, args), promise: (...args) => exports.promise(tapable, name, args), }; } } } }; exports.tap = (tapable, name, reason, callback) => { if (tapable.hooks) { tapable.hooks[name].tap(reason, callback); } else { if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) { const registration = knownPluginRegistrations[tapable.constructor.name][name]; exports.register(tapable, name, registration[0], registration[1]); } const dashName = tapable.__hardSource_hooks[name].dashName; if (tapable.__hardSource_hooks[name].async) { tapable.plugin(dashName, (...args) => { const cb = args.pop(); cb(null, callback(...args)); }); } else { tapable.plugin(dashName, callback); } } }; exports.tapPromise = (tapable, name, reason, callback) => { if (tapable.hooks) { tapable.hooks[name].tapPromise(reason, callback); } else { if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) { const registration = knownPluginRegistrations[tapable.constructor.name][name]; exports.register(tapable, name, registration[0], registration[1]); } const dashName = tapable.__hardSource_hooks[name].dashName; tapable.plugin(dashName, (...args) => { const cb = args.pop(); return callback(...args).then(value => cb(null, value), cb); }); } }; exports.tapAsync = (tapable, name, reason, callback) => { if (tapable.hooks) { tapable.hooks[name].tapAsync(reason, callback); } else { if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) { const registration = knownPluginRegistrations[tapable.constructor.name][name]; exports.register(tapable, name, registration[0], registration[1]); } const dashName = tapable.__hardSource_hooks[name].dashName; tapable.plugin(dashName, callback); } }; exports.call = (tapable, name, args) => { if (tapable.hooks) { const hook = tapable.hooks[name]; return hook.call(...args); } else { const dashName = tapable.__hardSource_hooks[name].dashName; const style = tapable.__hardSource_hooks[name].style; return tapable[callStyles[style]](...[dashName].concat(args)); } }; exports.promise = (tapable, name, args) => { if (tapable.hooks) { const hook = tapable.hooks[name]; return hook.promise(...args); } else { const dashName = tapable.__hardSource_hooks[name].dashName; const style = tapable.__hardSource_hooks[name].style; return new Promise((resolve, reject) => { tapable[callStyles[style]]( ...[dashName].concat(args, (err, value) => { if (err) { reject(err); } else { resolve(value); } }), ); }); } }; exports.tapFor = (tapable, name, key, reason, callback) => { if (tapable.hooks) { tapable.hooks[name].for(key).tap(reason, callback); } else { exports.tap(tapable, name, reason, callback); } }; exports.tapPromiseFor = (tapable, name, key, reason, callback) => { if (tapable.hooks) { tapable.hooks[name].for(key).tapPromise(reason, callback); } else { exports.tapPromise(tapable, name, reason, callback); } }; exports.callFor = (tapable, name, key, args) => { if (tapable.hooks) { tapable.hooks[name].for(key).call(...args); } else { exports.call(tapable, name, args); } }; exports.promiseFor = (tapable, name, key, args) => { if (tapable.hooks) { tapable.hooks[name].for(key).promise(...args); } else { exports.promise(tapable, name, args); } }; exports.hooks = tapable => { if (tapable.hooks) { return tapable.hooks; } if (!tapable.__hardSource_proxy) { tapable.__hardSource_proxy = {}; } const registrations = knownPluginRegistrations[tapable.constructor.name]; if (registrations) { for (const name in registrations) { const registration = registrations[name]; exports.register(tapable, name, registration[0], registration[1]); } } return tapable.__hardSource_proxy; };