Skip to content

Commit

Permalink
Implemented bugfix sugested by tsippert at [Github](AlbertoFdzM#81 (c…
Browse files Browse the repository at this point in the history
  • Loading branch information
migonos0 committed Feb 7, 2022
1 parent b5b209f commit d6bfb90
Showing 1 changed file with 81 additions and 89 deletions.
170 changes: 81 additions & 89 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
const regExpToParseExpressPathRegExp = /^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(\[\^\\\/]\+\?\)\)))\\\/.*/
const regExpToReplaceExpressPathRegExpParams = /\(\?:\(\[\^\\\/]\+\?\)\)/
const regexpExpressParamRegexp = /\(\?:\(\[\^\\\/]\+\?\)\)/g
const regExpToParseExpressPathRegExp =
/^\/\^\\\/(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\(\[\^\\\/]\+\?\)\)))\\\/.*/;
const regExpToReplaceExpressPathRegExpParams = /\(\?:\(\[\^\\\/]\+\?\)\)/;
const regexpExpressParamRegexp = /\(\?:\(\[\^\\\/]\+\?\)\)/g;

const EXPRESS_ROOT_PATH_REGEXP_VALUE = '/^\\/?(?=\\/|$)/i'
const STACK_ITEM_VALID_NAMES = [
'router',
'bound dispatch',
'mounted_app'
]
const EXPRESS_ROOT_PATH_REGEXP_VALUE = "/^\\/?(?=\\/|$)/i";
const STACK_ITEM_VALID_NAMES = ["router", "bound dispatch", "mounted_app"];

/**
* Returns all the verbs detected for the passed route
*/
const getRouteMethods = function (route) {
let methods = Object.keys(route.methods)
let methods = Object.keys(route.methods);

methods = methods.filter((method) => method !== '_all')
methods = methods.map((method) => method.toUpperCase())
methods = methods.filter((method) => method !== "_all");
methods = methods.map((method) => method.toUpperCase());

return methods
}
return methods;
};

/**
* Returns the names (or anonymous) of all the middlewares attached to the
Expand All @@ -29,78 +26,80 @@ const getRouteMethods = function (route) {
*/
const getRouteMiddlewares = function (route) {
return route.stack.map((item) => {
return item.handle.name || 'anonymous'
})
}
return item.handle.name || "anonymous";
});
};

/**
* Returns true if found regexp related with express params
* @param {string} expressPathRegExp
* @returns {boolean}
*/
const hasParams = function (expressPathRegExp) {
return regexpExpressParamRegexp.test(expressPathRegExp)
}
return regexpExpressParamRegexp.test(expressPathRegExp);
};

/**
* @param {Object} route Express route object to be parsed
* @param {string} basePath The basePath the route is on
* @return {Object[]} Endpoints info
*/
const parseExpressRoute = function (route, basePath) {
const paths = []
const paths = [];

if (Array.isArray(route.path)) {
paths.push(...route.path)
paths.push(...route.path);
} else {
paths.push(route.path)
paths.push(route.path);
}

const endpoints = paths.map((path) => {
const completePath = basePath && path === '/'
? basePath
: `${basePath}${path}`
const completePath =
basePath && path === "/" ? basePath : `${basePath}${path}`;

const endpoint = {
path: completePath,
methods: getRouteMethods(route),
middlewares: getRouteMiddlewares(route)
}
middlewares: getRouteMiddlewares(route),
};

return endpoint
})
return endpoint;
});

return endpoints
}
return endpoints;
};

/**
* @param {RegExp} expressPathRegExp
* @param {Object[]} params
* @returns {string}
*/
const parseExpressPath = function (expressPathRegExp, params) {
let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(expressPathRegExp)
let parsedRegExp = expressPathRegExp.toString()
let paramIndex = 0
let expressPathRegExpExec =
regExpToParseExpressPathRegExp.exec(expressPathRegExp);
let parsedRegExp = expressPathRegExp.toString();
let paramIndex = 0;

while (hasParams(parsedRegExp)) {
const paramName = params[paramIndex].name
const paramId = `:${paramName}`
const paramName = params[paramIndex].name;
const paramId = `:${paramName}`;

parsedRegExp = parsedRegExp
.replace(regExpToReplaceExpressPathRegExpParams, paramId)
parsedRegExp = parsedRegExp.replace(
regExpToReplaceExpressPathRegExpParams,
paramId
);

paramIndex++
paramIndex++;
}

if (parsedRegExp !== expressPathRegExp.toString()) {
expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp)
expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);
}

const parsedPath = expressPathRegExpExec[1].replace(/\\\//g, '/')
const parsedPath = expressPathRegExpExec[1].replace(/\\\//g, "/");

return parsedPath
}
return parsedPath;
};

/**
* @param {Object} app
Expand All @@ -109,23 +108,25 @@ const parseExpressPath = function (expressPathRegExp, params) {
* @returns {Object[]}
*/
const parseEndpoints = function (app, basePath, endpoints) {
const stack = app.stack || (app._router && app._router.stack)
const stack = app.stack || (app._router && app._router.stack);

endpoints = endpoints || []
basePath = basePath || ''
endpoints = endpoints || [];
basePath = basePath || "";

if (!stack) {
endpoints = addEndpoints(endpoints, [{
path: basePath,
methods: [],
middlewares: []
}])
endpoints = addEndpoints(endpoints, [
{
path: basePath,
methods: [],
middlewares: [],
},
]);
} else {
endpoints = parseStack(stack, basePath, endpoints)
endpoints = parseStack(stack, basePath, endpoints);
}

return endpoints
}
return endpoints;
};

/**
* Ensures the path of the new endpoints isn't yet in the array.
Expand All @@ -137,24 +138,9 @@ const parseEndpoints = function (app, basePath, endpoints) {
* @returns {Object[]} Updated endpoints array
*/
const addEndpoints = function (currentEndpoints, endpointsToAdd) {
endpointsToAdd.forEach((newEndpoint) => {
const existingEndpoint = currentEndpoints.find(
(item) => item.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
}
currentEndpoints.push(...endpointsToAdd);
return currentEndpoints;
};

/**
* @param {Object} stack
Expand All @@ -165,39 +151,45 @@ const addEndpoints = function (currentEndpoints, endpointsToAdd) {
const parseStack = function (stack, basePath, endpoints) {
stack.forEach((stackItem) => {
if (stackItem.route) {
const newEndpoints = parseExpressRoute(stackItem.route, basePath)
const newEndpoints = parseExpressRoute(stackItem.route, basePath);

endpoints = addEndpoints(endpoints, newEndpoints)
endpoints = addEndpoints(endpoints, newEndpoints);
} else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {
const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(stackItem.regexp)
const isExpressPathRegexp = regExpToParseExpressPathRegExp.test(
stackItem.regexp
);

let newBasePath = basePath
let newBasePath = basePath;

if (isExpressPathRegexp) {
const parsedPath = parseExpressPath(stackItem.regexp, stackItem.keys)
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 += `/${parsedPath}`;
} else if (
!stackItem.path &&
stackItem.regexp &&
stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE
) {
const regExpPath = ` RegExp(${stackItem.regexp}) `;

newBasePath += `/${regExpPath}`
newBasePath += `/${regExpPath}`;
}

endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints)
endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);
}
})
});

return endpoints
}
return endpoints;
};

/**
* Returns an array of strings with all the detected endpoints
* @param {Object} app the express/route instance to get the endpoints from
*/
const getEndpoints = function (app) {
const endpoints = parseEndpoints(app)
const endpoints = parseEndpoints(app);

return endpoints
}
return endpoints;
};

module.exports = getEndpoints
module.exports = getEndpoints;

0 comments on commit d6bfb90

Please sign in to comment.