import { removeTailSlash } from '@modern-js/utils' ; import { MatchFunction , MatchResult , match , pathToRegexp , } from 'path-to-regexp' ; import { ModernRoute , ModernRouteInterface } from './route' ; const regCharsDetector = /[^a-zA-Z\-_0-9\/\.]/ ; export class RouteMatcher { public spec : ModernRouteInterface ; public urlPath : string = '' ; public urlMatcher ? : MatchFunction ; public urlReg ? : RegExp ; constructor ( spec ) { this . spec = spec ; this . setupUrlPath ( ) ; } public generate ( ) { return new ModernRoute ( this . spec ) ; } public parseURLParams ( pathname ) { if ( ! this . urlMatcher ) { return { } ; } else { const matchResult = this . urlMatcher ( pathname ) ; return ( matchResult as MatchResult < Record < string , string > > ) . params ; } } public matchLength ( pathname ) { if ( ! this . urlReg ) { return this . urlPath . length ; } else { const result = this . urlReg . exec ( pathname ) ; return result ?. [ 0 ] ?. length || null ; } } public matchUrlPath ( requestUrl ) { const urlWithoutSlash = requestUrl . endsWith ( '/' ) && requestUrl !== '/' ? requestUrl . slice ( 0 , - 1 ) : requestUrl ; if ( this . urlMatcher ) { return Boolean ( this . urlMatcher ( urlWithoutSlash ) ) ; } else { if ( urlWithoutSlash . startsWith ( this . urlPath ) ) { if ( this . urlPath !== '/' && urlWithoutSlash . length > this . urlPath . length && ! urlWithoutSlash . startsWith ( `${ this . urlPath }/` ) ) { return false ; } return true ; } return false ; } } public matchEntry ( entryName ) { return this . spec . entryName === entryName ; } private setupUrlPath ( ) { const { urlPath } = this . spec ; this . urlPath = urlPath === '/' ? urlPath : removeTailSlash ( urlPath ) ; const useReg = regCharsDetector . test ( urlPath ) ; if ( useReg ) { this . urlMatcher = match ( urlPath , { decode : decodeURIComponent } ) ; this . urlReg = pathToRegexp ( urlPath ) ; } } }