Skip to content

Commit

Permalink
Merge pull request #163 from znsio/inline-express-list-endpoints
Browse files Browse the repository at this point in the history
Inlining express-list-endpoints dependency
  • Loading branch information
harikrishnan83 authored Nov 26, 2024
2 parents b9e9056 + 5a57862 commit 130155a
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 23 deletions.
19 changes: 0 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"type-check:watch": "npm run type-check -- --watch",
"build": "npm test && rimraf dist && npm run build:types && npm run build:js",
"build:types": "tsc --emitDeclarationOnly",
"build:js": "babel src --out-dir dist --ignore 'src/**/__tests__/**/*.ts' --extensions \".ts,.tsx\" --source-maps inline",
"build:js": "babel src --out-dir dist --ignore 'src/**/__tests__/**/*.ts' --extensions \".ts,.js,.tsx\" --source-maps inline",
"test": "rimraf coverage && jest --coverage",
"prepack": "node src/downloadSpecmaticJar.js",
"prepare": "npm run prepack && npm run build:types && npm run build:js"
Expand Down Expand Up @@ -48,7 +48,6 @@
},
"dependencies": {
"axios": "^1.7.7",
"express-list-endpoints": "github:znsio/express-list-endpoints#21c92d15159abffd772acb27027ab84fcec1a6ac",
"fast-xml-parser": "^4.5.0",
"terminate": "^2.8.0",
"tree-kill": "^1.2.2",
Expand All @@ -61,7 +60,6 @@
"@babel/preset-env": "^7.25.4",
"@babel/preset-typescript": "^7.24.7",
"@types/express": "^5.0.0",
"@types/express-list-endpoints": "github:znsio/express-list-endpoints#21c92d15159abffd772acb27027ab84fcec1a6ac",
"@types/jest": "^29.5.13",
"@types/jest-when": "^3.5.5",
"@types/node": "^22.7.2",
Expand Down
2 changes: 1 addition & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { XMLParser } from 'fast-xml-parser'
import fs from 'fs'
import logger from '../common/logger'
import { callCore } from '../common/runner'
import listExpressEndpoints from 'express-list-endpoints'
import listExpressEndpoints from '../lib/express-list-endpoints';
import http from 'http'
import { AddressInfo } from 'net'
import { gracefulShutdown } from './shutdownUtils'
Expand Down
15 changes: 15 additions & 0 deletions src/lib/express-list-endpoints/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export = expressListEndpoints;
declare function expressListEndpoints(app: import('express').Express | import('express').Router | any): Endpoint[];
declare namespace expressListEndpoints {
export { Route, Endpoint };
}
type Endpoint = {
path: string;
methods: string[];
middlewares: string[];
};
type Route = {
methods: Object;
path: string | string[];
stack: any[];
};
128 changes: 128 additions & 0 deletions src/lib/express-list-endpoints/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
const regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
const regexpExpressParamRegexp = /\(\?:\\?\\?\/?\([^)]+\)\)/g;
const regexpExpressPathParamRegexp = /(:[^)]+)\([^)]+\)/g;
const EXPRESS_ROOT_PATH_REGEXP_VALUE = '/^\\/?(?=\\/|$)/i';
const STACK_ITEM_VALID_NAMES = [
'router',
'bound dispatch',
'mounted_app'
];
const getRouteMethods = function (route) {
let methods = Object.keys(route.methods);
methods = methods.filter((method) => method !== '_all');
methods = methods.map((method) => method.toUpperCase());
return methods;
};
const getRouteMiddlewares = function (route) {
return route.stack.map((item) => {
return item.handle.name || 'anonymous';
});
};
const hasParams = function (expressPathRegExp) {
return regexpExpressParamRegexp.test(expressPathRegExp);
};
function combinePaths(base, path) {
return (base + path).replace(/\/+/g, "/").replace(/\/$/, "") || "/";
}
const parseExpressRoute = function (route, basePath) {
const paths = [];
if (Array.isArray(route.path)) {
paths.push(...route.path);
}
else {
paths.push(route.path);
}
const endpoints = paths.map((path) => {
const completePath = combinePaths(basePath, path);
const endpoint = {
path: completePath.replace(regexpExpressPathParamRegexp, '$1'),
methods: getRouteMethods(route),
middlewares: getRouteMiddlewares(route)
};
return endpoint;
});
return endpoints;
};
const parseExpressPath = function (expressPathRegExp, params) {
let parsedRegExp = expressPathRegExp.toString();
let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
let paramIndex = 0;
while (hasParams(parsedRegExp)) {
const paramName = params[paramIndex].name;
const paramId = `:${paramName}`;
parsedRegExp = parsedRegExp
.replace(regExpToReplaceExpressPathRegExpParams, (str) => {
if (str.startsWith('(?:\\/')) {
return `\\/${paramId}`;
}
return paramId;
});
paramIndex++;
}
if (parsedRegExp !== expressPathRegExp.toString()) {
expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
}
const parsedPath = expressPathRegExpExec[1].replace(/\\\//g, '/');
return parsedPath;
};
const parseEndpoints = function (app, basePath, endpoints) {
const stack = app.stack || (app._router && app._router.stack);
endpoints = endpoints || [];
basePath = basePath || '';
if (!stack) {
if (endpoints.length) {
endpoints = addEndpoints(endpoints, [{
path: basePath,
methods: [],
middlewares: []
}]);
}
}
else {
endpoints = parseStack(stack, basePath, endpoints);
}
return endpoints;
};
const addEndpoints = function (currentEndpoints, endpointsToAdd) {
endpointsToAdd.forEach((newEndpoint) => {
const existingEndpoint = currentEndpoints.find((endpoint) => endpoint.path === newEndpoint.path);
if (existingEndpoint !== undefined) {
const newMethods = newEndpoint.methods.filter((method) => !existingEndpoint.methods.includes(method));
existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);
}
else {
currentEndpoints.push(newEndpoint);
}
});
return currentEndpoints;
};
const parseStack = function (stack, basePath, endpoints) {
stack.forEach((stackItem) => {
if (stackItem.route) {
const newEndpoints = parseExpressRoute(stackItem.route, basePath);
endpoints = addEndpoints(endpoints, newEndpoints);
}
else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {
const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(stackItem.regexp);
let newBasePath = basePath;
if (isExpressPathRegexp) {
const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys);
newBasePath += `/${parsedPath}`;
}
else if (!stackItem.path && stackItem.regexp && stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE) {
const regExpPath = ` RegExp(${stackItem.regexp}) `;
newBasePath += `/${regExpPath}`;
}
endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);
}
});
return endpoints;
};
const expressListEndpoints = function (app) {
const endpoints = parseEndpoints(app);
return endpoints;
};
module.exports = expressListEndpoints;

0 comments on commit 130155a

Please sign in to comment.