/**
* @summary match-route-middleware
* @version 3.0.0
* @since 1.0.0
* @author Arian Khosravi <arian.khosravi@aofl.com>
*/
import PathUtils from '../path-utils';
/**
* Evaluates and returns the best matching route for the given path
*
* @memberof module:@aofl/router
*
* @param {String} _path
* @param {Array} routes
* @return {Object}
*/
const matchBestPath = (_path, routes) => {
const path = PathUtils.removeTrailingSlash(PathUtils.cleanPath(_path));
const stack = [];
for (let i = 0; i < routes.length; i++) {
const route = routes[i];
route.path = PathUtils.removeTrailingSlash(PathUtils.cleanPath(route.path));
if (path === route.path) { // exact match
stack.shift();
stack.push(route);
break;
}
const matches = route.regex.exec(path);
if (matches !== null) {
if (stack.length === 0) {
stack.push(route);
} else {
const pathSegments = PathUtils.getPathSegments(path);
const routeSegments = PathUtils.getPathSegments(route.path);
const lastSegments = PathUtils.getPathSegments(stack[0].path);
const routeSegmentMatchesCount = PathUtils.matchingSegmentsCount(pathSegments, routeSegments);
const lastSegmentMatchesCount = PathUtils.matchingSegmentsCount(pathSegments, lastSegments);
if (routeSegmentMatchesCount > lastSegmentMatchesCount) {
stack.shift();
stack.push(route);
}
}
}
}
const match = stack.shift();
if (!match) { return null; }
return Object.assign({}, match);
};
/**
* Adds the match route before middleware logic
*
* @memberof module:@aofl/router
*
* @param {Object} router
* @return {Function}
*/
export default (router) => (request, response, next) => {
const matchedRoute = matchBestPath(request.to, request.routes);
let currentRoute = null;
if (matchedRoute !== null) {
matchedRoute.props = matchedRoute.parse(request.to);
currentRoute = Object.assign({}, response, {matchedRoute});
} else {
currentRoute = Object.assign({}, response, {matchedRoute: null});
}
router.currentRoute = currentRoute; // add MatchedRoute to the router instance
next(currentRoute);
};