wegweiser
Version:
A router for Quinn
102 lines (81 loc) • 2.77 kB
JavaScript
;
const routington = require('routington');
const Annotation = require('footnote'),
scan = Annotation.scan,
createAnnotation = Annotation.create;
const METHODS = [ 'GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS' ];
const slice = Array.prototype.slice;
function Route(method, url, callsiteError) {
return createAnnotation(Route.prototype, {
method: { value: method, enumerable: true },
url: { value: url, enumerable: true },
callsiteError: { value: callsiteError },
});
}
function getPathname(url) { return url.split('?')[0]; }
function createHandler(result) {
if (typeof result.ctor === 'function') {
const ctor = result.ctor, key = result.key;
const constructAndHandle = function constructAndHandle(req, params) {
const instance = new ctor(req);
return instance[key](req, params);
};
constructAndHandle.ctor = ctor;
constructAndHandle.key = key;
return constructAndHandle;
} else if (result.ctx !== null && typeof result.ctx === 'object') {
const ctx = result.ctx, key = result.key;
const applyHandlerToContext = function applyHandlerToContext(req, params) {
return ctx[key](req, params);
};
applyHandlerToContext.ctx = ctx;
applyHandlerToContext.key = key;
return applyHandlerToContext;
}
return result.target;
}
function createRouter() {
const targets = slice.call(arguments);
const router = routington();
for (let target of targets) {
for (let result of scan(target, Route)) {
const a = result.annotation,
method = a.method,
url = a.url,
callsiteError = a.callsiteError;
const node = router.define(url)[0];
if (node[method]) {
const error = callsiteError || new Error();
error.message =
`Ambiguous route definition for ${method} ${url}`;
throw error;
}
node[method] = createHandler(result);
}
}
function resolve(req) {
const match = router.match(getPathname(req.url));
const handler = match && match.node[req.method];
if (!handler) return;
return { handler: handler, params: match.param };
}
function route(req) {
const resolved = resolve(req);
if (!resolved) return;
const handler = resolved.handler;
return handler(req, resolved.params);
}
route.resolve = resolve;
return route;
}
METHODS.forEach(function(method) {
createRouter[method] = function METHOD(url) {
const callsiteError = new Error();
Error.captureStackTrace(callsiteError, METHOD);
return Route(method, url, callsiteError);
};
});
createRouter.Route = Route;
module.exports = createRouter;
createRouter['default'] = createRouter;
createRouter.createRouter = createRouter;