tapable/lib/AsyncParallelHook.js
2017-08-29 16:27:59 +02:00

186 lines
4.8 KiB
JavaScript

"use strict";
const Hook = require("./Hook");
const simpleAsyncCases = require("./simpleAsyncCases");
class AsyncParallelHook extends Hook {
constructor(args) {
super(args);
this.call = this._call = undefined;
}
template(options) {
const simpleCase = simpleAsyncCases.notBailing(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 _remaining = _fns.length;
const _handler = (_err) => {
if(_err && _remaining > 0) {
_remaining = -1;
_callback(_err);
return;
}
if(--_remaining === 0) {
_callback();
}
};
for(let _i = 0; _i < _fns.length; _i++) {
_fns[_i](${argsWithComma}_handler);
}
}`;
case "multiple-async promise":
return `function(${args}) {
return new Promise((_resolve, _reject) => {
const _fns = this._x;
let _remaining = _fns.length;
const _handler = (_err) => {
if(_err && _remaining > 0) {
_remaining = -1;
_reject(_err);
return;
}
if(--_remaining === 0) {
_resolve();
}
};
for(let _i = 0; _i < _fns.length; _i++) {
_fns[_i](${argsWithComma}_handler);
}
});
}`;
case "multiple-promise async":
return `function(${argsWithCallback}) {
const _fns = this._x;
let _remaining = _fns.length;
const _handler = () => {
if(--_remaining === 0) {
_callback();
}
}
const _handlerErr = (_err) => {
if(_remaining > 0) {
_remaining = -1;
_callback(_err);
}
}
for(let _i = 0; _i < _fns.length; _i++) {
Promise.resolve(_fns[_i](${args})).then(_handler, _handlerErr);
}
}`;
case "multiple-promise promise":
return `function(${args}) {
const _fns = this._x;
return Promise.all(_fns.map(_fn => _fn(${args}))).then(() => {});
}`;
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});
` : ""}
let _remaining = _taps.length;
const _handler = (_err) => {
if(_err && _remaining > 0) {
_remaining = -1;
_callback(_err);
return;
}
if(--_remaining === 0) {
_callback();
}
};
const _handlerSuccess = () => {
if(--_remaining === 0) {
_callback();
}
}
const _handlerErr = (_err) => {
if(_remaining > 0) {
_remaining = -1;
_callback(_err);
}
}
for(let _i = 0; _i < _taps.length; _i++) {
${isInspect ? `let _tap = _taps[_i];
for(let _j = 0; _j < _inspect.length; _j++)
_tap = _inspect[_j].tap(_tap);
` : `const _tap = _taps[_i];`}
switch(_tap.type) {
case "sync":
try {
_tap.fn(${args});
} catch(_err) {
_handlerErr(_err);
break;
}
_handlerSuccess();
break;
case "async":
_tap.fn(${argsWithComma}_handler);
break;
case "promise":
Promise.resolve(_tap.fn(${args})).then(_handlerSuccess, _handlerErr);
break;
}
}
}`;
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});
` : ""}
let _earlyAbort = false;
return Promise.all(_taps.map(_tap => {
if(_earlyAbort) return;
${isInspect ? `for(let _j = 0; _j < _inspect.length; _j++)
_tap = _inspect[_j].tap(_tap);
` : ""}
switch(_tap.type) {
case "sync":
try {
_tap.fn(${args});
} catch(_err) {
_earlyAbort = true;
return Promise.reject(_err);
}
return Promise.resolve();
case "async":
return new Promise((_resolve, _reject) => {
_tap.fn(${argsWithComma}_err => {
if(_err) {
_earlyAbort = true;
_reject(_err);
return;
}
_resolve();
});
});
break;
case "promise":
return _tap.fn(${args});
break;
}
})).then(() => {});
}`;
default:
throw new Error(`Unsupported tap '${tap}' or type '${type}'`);
}
}
}
module.exports = AsyncParallelHook;