file-routing-expressjs
Version:
A dependency-free, flexible, system-based file routing for Express.
172 lines • 6.4 kB
JavaScript
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var import_meta = {};
import { fileURLToPath } from "url";
import path from "path";
var getFilename = () => fileURLToPath(import_meta.url);
var getDirname = () => path.dirname(getFilename());
var __dirname = /* @__PURE__ */ getDirname();
var __filename = /* @__PURE__ */ getFilename();
import fs from "fs";
import path2 from "path";
import { extractDirContext, extractEndpointName, extractFileContext } from "../helpers/extractors";
import { buildRoutePattern, buildRouteWithOneLeadingSlash } from "../helpers/builders";
import { filenameIsJSorTS, functionIsExceptionHandler, functionIsRequestHandler, methodIsExpressMethod } from "../helpers/validators";
class FileBasedRouting {
constructor({ app, target }) {
this.base = target || path2.resolve(__dirname, "src", "routes");
this._app = app;
this.endpoints = [];
this._currentDepth = 0;
}
createRoutes() {
return __async(this, null, function* () {
this.mapRoutes({
target: this.base,
route: "/",
parentConfig: void 0
});
});
}
mapRoutes(_0) {
return __async(this, arguments, function* ({ target, route, parentConfig }) {
var _a;
if (!fs.existsSync(target)) {
return;
}
let parent = ((_a = parentConfig == null ? void 0 : parentConfig.route) == null ? void 0 : _a.trim()) || "/";
const targetStat = fs.statSync(target);
const basename = path2.basename(target.replace(this.base, ""));
const { name, isParam } = extractEndpointName(path2.parse(basename).name);
route = buildRouteWithOneLeadingSlash(route);
if (targetStat.isDirectory()) {
return this.handleDir({ route, parent, name, basename, target, isParam });
}
if (targetStat.isFile()) {
return this.handleFile({ route, name, basename, target, isParam });
}
});
}
handleDir({ route, parent, name, basename, target, isParam }) {
parent = path2.join(parent, basename);
const routes = fs.readdirSync(target);
const { config, middlewares, errorHandler } = extractDirContext(target);
const endpoint = buildRoutePattern(route, name, isParam, typeof (config == null ? void 0 : config.pattern) === "string" || config.pattern instanceof RegExp ? config.pattern : void 0);
middlewares.forEach((middleware) => this._app.use(endpoint, middleware));
this.endpoints.push({
depth: this._currentDepth++,
name,
endpoint,
method: "-",
middlewares: middlewares.map((item) => item.name),
errorHandler: (errorHandler == null ? void 0 : errorHandler.name) || "-"
});
routes.forEach((item) => {
if (item.startsWith("_")) return;
const newTarget = path2.join(target, item);
if (!fs.existsSync(newTarget)) return;
this.mapRoutes({
target: newTarget,
route: endpoint,
parentConfig: {
route: parent
}
});
});
this._currentDepth--;
if (errorHandler) this._app.use(endpoint, errorHandler);
}
handleFile(_0) {
return __async(this, arguments, function* ({ route, name, basename, target, isParam }) {
var _a, _b;
if (!filenameIsJSorTS(basename)) return;
const module = yield import(target);
if (!module) return;
const handlers = {
get: module._get,
post: module._post,
delete: module._delete,
put: module._put,
patch: module._patch,
all: module._all
};
let { config, middlewares, errorHandler } = extractFileContext(target);
const entries = Object.entries(handlers);
for (const [method, handler] of entries) {
if (!methodIsExpressMethod(method) || !functionIsRequestHandler(handler)) continue;
const endpoint = buildRoutePattern(
route,
name,
isParam,
config.pattern instanceof RegExp || typeof config.pattern === "string" ? config.pattern : ((_a = config.pattern) == null ? void 0 : _a[method]) || ((_b = config.pattern) == null ? void 0 : _b.all),
true
);
const routerEndpoint = {
depth: this._currentDepth,
name,
endpoint,
method,
middlewares: [],
errorHandler: "-"
};
const routeMiddlewares = [];
if (Array.isArray(middlewares)) {
middlewares.forEach((middleware) => {
routeMiddlewares.push(middleware);
routerEndpoint.middlewares.push(middleware.name);
});
} else if (typeof middlewares === "object") {
const methodMiddlwares = middlewares[method] || middlewares.all;
if (!Array.isArray(methodMiddlwares)) {
if (methodMiddlwares) {
routeMiddlewares.push(methodMiddlwares);
routerEndpoint.middlewares.push(methodMiddlwares.name);
}
} else {
methodMiddlwares == null ? void 0 : methodMiddlwares.forEach((middleware) => {
routeMiddlewares.push(middleware);
routerEndpoint.middlewares.push(middleware.name);
});
}
} else {
routeMiddlewares.push(middlewares);
routerEndpoint.middlewares.push(middlewares.name);
}
this._app[method](endpoint, ...routeMiddlewares, handler);
if (errorHandler) {
if (typeof errorHandler !== "function") {
errorHandler = errorHandler[method] && errorHandler.all;
}
if (functionIsExceptionHandler(errorHandler)) {
this._app.use(endpoint, errorHandler);
routerEndpoint.errorHandler = errorHandler.name;
}
}
this.endpoints.push(routerEndpoint);
}
});
}
}
var fileBasedRouting_default = FileBasedRouting;
export {
fileBasedRouting_default as default
};
//# sourceMappingURL=fileBasedRouting.mjs.map