UNPKG

actionhero

Version:

The reusable, scalable, and quick node.js API server for stateless and stateful applications

167 lines (166 loc) 7.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RoutesInitializer = void 0; const path = require("path"); const index_1 = require("../index"); const route_1 = require("../modules/route"); /** * Contains routing options for web clients. Can associate routes with actions or files. */ class RoutesInitializer extends index_1.Initializer { constructor() { super(); this.processRoute = (connection, pathParts) => { var _a; if (connection.params.action === undefined || index_1.api.actions.actions[connection.params.action] === undefined) { let method = connection.rawConnection.method.toLowerCase(); if (method === "head" && !index_1.api.routes.routes.head) method = "get"; for (const i in index_1.api.routes.routes[method]) { const route = index_1.api.routes.routes[method][i]; const match = index_1.api.routes.matchURL(pathParts, route.path, route.matchTrailingPathParts); if (match.match) { if (route.apiVersion) { (_a = connection.params).apiVersion || (_a.apiVersion = route.apiVersion); } for (const param in match.params) { try { const decodedName = decodeURIComponent(param.replace(/\+/g, " ")); const decodedValue = decodeURIComponent(match.params[param].replace(/\+/g, " ")); connection.params[decodedName] = decodedValue; } catch (e) { // malformed URL } } connection.matchedRoute = route; if (route.dir) { const requestedFile = connection.rawConnection.parsedURL.pathname.substring(route.path.length, connection.rawConnection.parsedURL.pathname.length); connection.params.file = path.normalize(route.dir + "/" + requestedFile); } else { connection.params.action = route.action; } break; } } } }; this.matchURL = (pathParts, match, matchTrailingPathParts) => { const response = { match: false, params: {}, }; const matchParts = match.split("/"); let regexpMatch = null; let variable = ""; if (matchParts[0] === "") matchParts.splice(0, 1); if (matchParts[matchParts.length - 1] === "") matchParts.pop(); if (matchParts.length !== pathParts.length && !matchTrailingPathParts) { return response; } for (const i in matchParts) { const matchPart = matchParts[i]; let pathPart = pathParts[i]; if (matchTrailingPathParts && parseInt(i) === matchParts.length - 1) { for (const j in pathParts) { if (j > i) pathPart = pathPart + "/" + pathParts[j]; } } if (!pathPart) return response; if (matchPart.includes(":")) { const trimmedMatchParts = matchPart.split(":"); const trimmedMatchPart = trimmedMatchParts[trimmedMatchParts.length - 1]; const replacement = trimmedMatchParts[trimmedMatchParts.length - 2]; if (replacement) { if (!pathPart.includes(replacement)) return response; pathPart = pathPart.replace(replacement, ""); } if (!trimmedMatchPart.includes("(")) { variable = trimmedMatchPart; response.params[variable] = pathPart; } else { variable = trimmedMatchPart.replace(":", "").split("(")[0]; regexpMatch = trimmedMatchPart.substring(trimmedMatchPart.indexOf("(") + 1, trimmedMatchPart.length - 1); const matches = pathPart.match(new RegExp(regexpMatch, "g")); if (matches) { response.params[variable] = pathPart; } else { return response; } } } else { if (pathPart === null || pathPart === undefined || pathParts[i].toLowerCase() !== matchPart.toLowerCase()) { return response; } } } response.match = true; return response; }; this.loadRoutes = (rawRoutes) => { let counter = 0; if (!rawRoutes) if (index_1.config.routes) rawRoutes = index_1.config.routes; for (const [method, collection] of Object.entries(rawRoutes)) { for (const configRoute of collection) { if (method === "all") { for (const verb of route_1.routerMethods) { index_1.route.registerRoute(verb, configRoute.path, configRoute.action, configRoute.apiVersion, configRoute.matchTrailingPathParts, configRoute.dir); } } else { index_1.route.registerRoute(method, configRoute.path, configRoute.action, configRoute.apiVersion, configRoute.matchTrailingPathParts, configRoute.dir); } counter++; } } index_1.api.params.postVariables = index_1.utils.arrayUnique(index_1.api.params.postVariables); if (index_1.config.web && Array.isArray(index_1.config.web.automaticRoutes)) { index_1.config.web.automaticRoutes.forEach((verb) => { if (!route_1.routerMethods.includes(verb)) { throw new Error(`${verb} is not an HTTP verb`); } (0, index_1.log)(`creating routes automatically for all actions responding to ${verb.toUpperCase()} HTTP verb`); for (const action in index_1.api.actions.actions) { index_1.route.registerRoute(verb, "/" + action, action, null); } }); } (0, index_1.log)("routes:", "debug", index_1.api.routes.routes); return counter; }; this.name = "routes"; this.loadPriority = 500; } async initialize() { index_1.api.routes = { routes: { all: [], head: [], get: [], patch: [], post: [], put: [], delete: [], }, processRoute: this.processRoute, matchURL: this.matchURL, loadRoutes: this.loadRoutes, }; index_1.api.routes.loadRoutes(); } } exports.RoutesInitializer = RoutesInitializer;