@nestjs/core
Version:
Nest - modern, fast, powerful node.js web framework (@core)
60 lines (59 loc) • 2.55 kB
JavaScript
import { RouteConflictDetector } from './route-conflict-detector.js';
/**
* Static utility class that orders resolved routes by specificity so the
* underlying HTTP adapter registers more specific patterns first.
* Stateless — every method takes everything it needs as parameters.
*/
export class RouteSpecificitySorter {
/**
* Lower rank means more specific. A literal segment beats a named
* param, which beats a named wildcard. A position that is absent on
* one side is the least specific of all (it means the path is shorter
* at that point).
*/
static SEGMENT_KIND_RANK = {
literal: 0,
param: 1,
wildcard: 2,
missing: 3,
};
/**
* Returns a new array of routes sorted from most-specific to
* least-specific. Routes that tie on specificity keep their original
* declaration order.
*/
static sort(routes) {
const decoratedRoutes = routes.map((route, declarationIndex) => ({
route,
declarationIndex,
}));
decoratedRoutes.sort((leftEntry, rightEntry) => {
const specificityDelta = RouteSpecificitySorter.comparePathSpecificity(leftEntry.route.path, rightEntry.route.path);
if (specificityDelta !== 0)
return specificityDelta;
return leftEntry.declarationIndex - rightEntry.declarationIndex;
});
return decoratedRoutes.map(decoratedEntry => decoratedEntry.route);
}
static comparePathSpecificity(leftPath, rightPath) {
const leftSegments = RouteConflictDetector.tokenizePath(leftPath);
const rightSegments = RouteConflictDetector.tokenizePath(rightPath);
const longestPathLength = Math.max(leftSegments.length, rightSegments.length);
let specificityDelta = 0;
Array.from({ length: longestPathLength }).forEach((_, segmentIndex) => {
if (specificityDelta !== 0)
return;
const leftKind = leftSegments[segmentIndex]?.kind ?? 'missing';
const rightKind = rightSegments[segmentIndex]?.kind ?? 'missing';
const leftRank = RouteSpecificitySorter.rankSegmentByKind(leftKind);
const rightRank = RouteSpecificitySorter.rankSegmentByKind(rightKind);
if (leftRank !== rightRank) {
specificityDelta = leftRank - rightRank;
}
});
return specificityDelta;
}
static rankSegmentByKind(kind) {
return RouteSpecificitySorter.SEGMENT_KIND_RANK[kind];
}
}