UNPKG

@nestjs/core

Version:

Nest - modern, fast, powerful node.js web framework (@core)

60 lines (59 loc) 2.55 kB
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]; } }