mirror of
https://github.com/webpack/tapable.git
synced 2026-01-18 14:28:32 +00:00
227 lines
6.2 KiB
JavaScript
227 lines
6.2 KiB
JavaScript
"use strict";
|
|
|
|
const Hook = require("./Hook");
|
|
const simpleAsyncCases = require("./simpleAsyncCases");
|
|
|
|
class AsyncParallelBailHook extends Hook {
|
|
constructor(args) {
|
|
super(args);
|
|
this.call = this._call = undefined;
|
|
}
|
|
|
|
template(options) {
|
|
const simpleCase = simpleAsyncCases.bailing(options);
|
|
if(simpleCase) return simpleCase;
|
|
const args = options.args.join(", ");
|
|
const argsWithCallback = args ? `${args}, _callback` : "_callback";
|
|
const argsWithComma = args ? `${args}, ` : "";
|
|
const tap = options.tap;
|
|
const type = options.type;
|
|
const isInspect = tap == "inspect";
|
|
switch(`${tap} ${type}`) {
|
|
case "multiple-async async":
|
|
return `function(${argsWithCallback}) {
|
|
const _fns = this._x;
|
|
let _done = new Set();
|
|
let _currentPos = _fns.length;
|
|
let _currentError, _currentResult;
|
|
for(let _i = 0; _i < _fns.length; _i++) {
|
|
if(_i >= _currentPos) return; // early ignore
|
|
_fns[_i](${argsWithComma}((_i) => (_err, _result) => {
|
|
if(_i >= _currentPos) return; // ignore
|
|
if(_err || _result !== undefined) {
|
|
_currentPos = _i;
|
|
for(const _k of _done)
|
|
if(_k >= _i)
|
|
_done.delete(_k);
|
|
_currentError = _err;
|
|
_currentResult = _result;
|
|
} else {
|
|
_done.add(_i);
|
|
}
|
|
if(_done.size === _currentPos) {
|
|
_currentPos = 0;
|
|
_callback(_currentError, _currentResult);
|
|
}
|
|
})(_i));
|
|
}
|
|
}`;
|
|
case "multiple-async promise":
|
|
return `function(${args}) {
|
|
return new Promise((_resolve, _reject) => {
|
|
const _fns = this._x;
|
|
let _done = new Set();
|
|
let _currentPos = _fns.length;
|
|
let _currentError, _currentResult;
|
|
for(let _i = 0; _i < _fns.length; _i++) {
|
|
if(_i >= _currentPos) return; // early ignore
|
|
_fns[_i](${argsWithComma}((_i) => (_err, _result) => {
|
|
if(_i >= _currentPos) return; // ignore
|
|
if(_err || _result !== undefined) {
|
|
_currentPos = _i;
|
|
for(const _k of _done)
|
|
if(_k >= _i)
|
|
_done.delete(_k);
|
|
_currentError = _err;
|
|
_currentResult = _result;
|
|
} else {
|
|
_done.add(_i);
|
|
}
|
|
if(_done.size === _currentPos) {
|
|
_currentPos = 0;
|
|
if(_currentError) {
|
|
_reject(_currentError);
|
|
return;
|
|
}
|
|
_resolve(_currentResult);
|
|
}
|
|
})(_i));
|
|
}
|
|
});
|
|
}`;
|
|
case "multiple-promise async":
|
|
return `function(${argsWithCallback}) {
|
|
const _fns = this._x;
|
|
const _promises = _fns.map(_fn => _fn(${args}));
|
|
Promise.race(_promises).catch(() => {}); // prevent unhandled rejections
|
|
let _i = 0;
|
|
(function _next() {
|
|
_promises[_i].then(_result => {
|
|
if(_result !== undefined) {
|
|
_callback(null, _result);
|
|
return;
|
|
}
|
|
if(++_i >= _promises.length) {
|
|
_callback();
|
|
return;
|
|
}
|
|
_next();
|
|
}, _err => {
|
|
_callback(_err);
|
|
});
|
|
}());
|
|
}`;
|
|
case "multiple-promise promise":
|
|
return `function(${args}) {
|
|
const _fns = this._x;
|
|
const _promises = _fns.map(_fn => _fn(${args}));
|
|
Promise.race(_promises).catch(() => {}); // prevent unhandled rejections
|
|
let _i = 0;
|
|
return (function _next() {
|
|
return _promises[_i].then(_result => {
|
|
if(_result !== undefined) {
|
|
return _result;
|
|
}
|
|
if(++_i >= _promises.length) {
|
|
return;
|
|
}
|
|
return _next();
|
|
});
|
|
}());
|
|
}`;
|
|
case "multiple async":
|
|
case "inspect async":
|
|
return `function(${argsWithCallback}) {
|
|
const _taps = this._x;
|
|
${isInspect ? `const _inspect = this.inspectors;
|
|
for(let _j = 0; _j < _inspect.length; _j++)
|
|
_inspect[_j].call(${args});
|
|
` : ""}
|
|
const _promises = _taps.map(_tap => {
|
|
${isInspect ? `for(let _j = 0; _j < _inspect.length; _j++)
|
|
_tap = _inspect[_j].tap(_tap);
|
|
` : ""}
|
|
switch(_tap.type) {
|
|
case "sync":
|
|
try {
|
|
return Promise.resolve(_tap.fn(${args}));
|
|
} catch(_err) {
|
|
return Promise.resolve().then(() => { throw _err; });
|
|
}
|
|
case "async":
|
|
return new Promise((_resolve, _reject) => {
|
|
_tap.fn(${argsWithComma}(_err, _result) => {
|
|
if(_err) {
|
|
_reject(_err);
|
|
return;
|
|
}
|
|
_resolve(_result);
|
|
});
|
|
});
|
|
case "promise":
|
|
return Promise.resolve(_tap.fn(${args}));
|
|
}
|
|
});
|
|
Promise.race(_promises).catch(() => {}); // prevent unhandled rejections
|
|
let _i = 0;
|
|
(function _next() {
|
|
_promises[_i].then(_result => {
|
|
if(_result !== undefined) {
|
|
_callback(null, _result);
|
|
return;
|
|
}
|
|
if(++_i >= _promises.length) {
|
|
_callback();
|
|
return;
|
|
}
|
|
_next();
|
|
}, _err => {
|
|
_callback(_err);
|
|
});
|
|
}());
|
|
}`;
|
|
case "multiple promise":
|
|
case "inspect promise":
|
|
return `function(${args}) {
|
|
const _taps = this._x;
|
|
${isInspect ? `const _inspect = this.inspectors;
|
|
for(let _j = 0; _j < _inspect.length; _j++)
|
|
_inspect[_j].call(${args});
|
|
` : ""}
|
|
const _promises = _taps.map(_tap => {
|
|
${isInspect ? `for(let _j = 0; _j < _inspect.length; _j++)
|
|
_tap = _inspect[_j].tap(_tap);
|
|
` : ""}
|
|
switch(_tap.type) {
|
|
case "sync":
|
|
try {
|
|
return Promise.resolve(_tap.fn(${args}));
|
|
} catch(_err) {
|
|
return Promise.resolve().then(() => { throw _err; });
|
|
}
|
|
case "async":
|
|
return new Promise((_resolve, _reject) => {
|
|
_tap.fn(${argsWithComma}(_err, _result) => {
|
|
if(_err) {
|
|
_reject(_err);
|
|
return;
|
|
}
|
|
_resolve(_result);
|
|
});
|
|
});
|
|
case "promise":
|
|
return Promise.resolve(_tap.fn(${args}));
|
|
}
|
|
});
|
|
Promise.race(_promises).catch(() => {}); // prevent unhandled rejections
|
|
let _i = 0;
|
|
return (function _next() {
|
|
return _promises[_i].then(_result => {
|
|
if(_result !== undefined) {
|
|
return _result;
|
|
}
|
|
if(++_i >= _promises.length) {
|
|
return;
|
|
}
|
|
return _next();
|
|
});
|
|
}());
|
|
}`;
|
|
default:
|
|
throw new Error(`Unsupported tap '${tap}' or type '${type}'`);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = AsyncParallelBailHook;
|