@segment/analytics.js-core
Version:
The hassle-free way to integrate analytics into any web application.
111 lines (93 loc) • 3.14 kB
text/typescript
;
var Facade = require('segmentio-facade');
module.exports.SourceMiddlewareChain = function SourceMiddlewareChain() {
var apply = middlewareChain(this);
this.applyMiddlewares = function(facade, integrations, callback) {
return apply(
function(mw, payload, next) {
mw({
integrations: integrations,
next: next,
payload: payload
});
},
facade,
callback
);
};
};
module.exports.IntegrationMiddlewareChain = function IntegrationMiddlewareChain() {
var apply = middlewareChain(this);
this.applyMiddlewares = function(facade, integration, callback) {
return apply(
function(mw, payload, next) {
mw(payload, integration, next);
},
facade,
callback
);
};
};
module.exports.DestinationMiddlewareChain = function DestinationMiddlewareChain() {
var apply = middlewareChain(this);
this.applyMiddlewares = function(facade, integration, callback) {
return apply(
function(mw, payload, next) {
mw({ payload: payload, integration: integration, next: next });
},
facade,
callback
);
};
};
// Chain is essentially a linked list of middlewares to run in order.
function middlewareChain(dest) {
var middlewares = [];
// Return a copy to prevent external mutations.
dest.getMiddlewares = function() {
return middlewares.slice();
};
dest.add = function(middleware) {
if (typeof middleware !== 'function')
throw new Error('attempted to add non-function middleware');
// Check for identical object references - bug check.
if (middlewares.indexOf(middleware) !== -1)
throw new Error('middleware is already registered');
middlewares.push(middleware);
};
// fn is the callback to be run once all middlewares have been applied.
return function applyMiddlewares(run, facade, callback) {
if (typeof facade !== 'object')
throw new Error('applyMiddlewares requires a payload object');
if (typeof callback !== 'function')
throw new Error('applyMiddlewares requires a function callback');
// Attach callback to the end of the chain.
var middlewaresToApply = middlewares.slice();
middlewaresToApply.push(callback);
executeChain(run, facade, middlewaresToApply, 0);
};
}
// Go over all middlewares until all have been applied.
function executeChain(run, payload, middlewares, index) {
// If the facade has been nullified, immediately skip to the final middleware.
if (payload === null) {
middlewares[middlewares.length - 1](null);
return;
}
// Check if the payload is still a Facade. If not, convert it to one.
if (!(payload instanceof Facade)) {
payload = new Facade(payload);
}
var mw = middlewares[index];
if (mw) {
// If there's another middleware, continue down the chain. Otherwise, call the final function.
if (middlewares[index + 1]) {
run(mw, payload, function(result) {
executeChain(run, result, middlewares, ++index);
});
} else {
mw(payload);
}
}
}
module.exports.middlewareChain = middlewareChain;