UNPKG

@whatwg-node/router

Version:
159 lines (154 loc) 5.51 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const DefaultFetchAPI = require('@whatwg-node/fetch'); const server = require('@whatwg-node/server'); const HTTP_METHODS = [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH', ]; function createRouterBase({ fetchAPI: givenFetchAPI, base: basePath = '/', } = {}) { const fetchAPI = { ...givenFetchAPI, ...DefaultFetchAPI, }; const routesByMethod = new Map(); function addHandlersToMethod(method, path, ...handlers) { let methodPatternMaps = routesByMethod.get(method); if (!methodPatternMaps) { methodPatternMaps = new Map(); routesByMethod.set(method, methodPatternMaps); } let fullPath = ''; if (basePath === '/') { fullPath = path; } else if (path === '/') { fullPath = basePath; } else { fullPath = `${basePath}${path}`; } const pattern = new fetchAPI.URLPattern({ pathname: fullPath }); methodPatternMaps.set(pattern, handlers); } async function handleRequest(request, context) { const method = request.method; let _parsedUrl; function getParsedUrl() { if (!_parsedUrl) { _parsedUrl = new fetchAPI.URL(request.url); } return _parsedUrl; } const methodPatternMaps = routesByMethod.get(method); if (methodPatternMaps) { const queryProxy = new Proxy({}, { get(_, prop) { const parsedUrl = getParsedUrl(); const allQueries = parsedUrl.searchParams.getAll(prop.toString()); return allQueries.length === 1 ? allQueries[0] : allQueries; }, has(_, prop) { const parsedUrl = getParsedUrl(); return parsedUrl.searchParams.has(prop.toString()); }, }); for (const [pattern, handlers] of methodPatternMaps) { const match = pattern.exec(request.url); if (match) { const routerRequest = new Proxy(request, { get(target, prop) { if (prop === 'parsedUrl') { return getParsedUrl(); } if (prop === 'params') { return new Proxy(match.pathname.groups, { get(_, prop) { const value = match.pathname.groups[prop.toString()]; if (value != null) { return decodeURIComponent(value); } return value; }, }); } if (prop === 'query') { return queryProxy; } const targetProp = target[prop]; if (typeof targetProp === 'function') { return targetProp.bind(target); } return targetProp; }, has(target, prop) { return (prop in target || prop === 'parsedUrl' || prop === 'params' || prop === 'query'); }, }); for (const handler of handlers) { const result = await handler(routerRequest, context); if (result) { return result; } } } } } } return new Proxy({}, { get(_, prop) { if (prop === 'handle') { return handleRequest; } const method = prop.toString().toLowerCase(); return function routeMethodKeyFn(path, ...handlers) { if (method === 'all') { for (const httpMethod of HTTP_METHODS) { addHandlersToMethod(httpMethod, path, ...handlers); } } else { addHandlersToMethod(method.toUpperCase(), path, ...handlers); } return this; }; }, }); } function createRouter(options) { const routerBaseObject = createRouterBase(options); return server.createServerAdapter(routerBaseObject, options); } Object.defineProperty(exports, 'Response', { enumerable: true, get: function () { return DefaultFetchAPI.Response; } }); Object.defineProperty(exports, 'URLPattern', { enumerable: true, get: function () { return DefaultFetchAPI.URLPattern; } }); Object.defineProperty(exports, 'useCORS', { enumerable: true, get: function () { return server.useCORS; } }); Object.defineProperty(exports, 'useErrorHandling', { enumerable: true, get: function () { return server.useErrorHandling; } }); exports.createRouter = createRouter; exports.createRouterBase = createRouterBase;