Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 2x 2x 6x 6x 6x 6x 6x 6x 2x 6x 190x 190x 2x 2x 166x 166x 190x 190x 190x 190x 190x 164x 190x 188x 24x 20x 184x 184x 184x 184x 36x 184x 184x 50x 184x 2x 182x 2x 180x 156x 2x 4x 4x 156x | import { ParseRoutesOptions, Protocol, Route, RouteParam } from './types' import { validateProtocol } from './validation' import { InvalidPatternError } from './errors' function routeSpecificity(url: URL) { // Adapted from internal config service routing table implementation const hostParts = url.host.split('.') let hostScore = hostParts.length Iif (hostParts[0] === '*') { hostScore -= 2 } const pathParts = url.pathname.split('/') let pathScore = pathParts.length if (pathParts[pathParts.length - 1] === '*') { pathScore -= 2 } // The magic 26 comes directly from the cloudflare algorithm from workers-sdk return hostScore * 26 + pathScore } function parsePatternUrl(pattern: string): URL { try { return new URL(pattern) } catch { throw new InvalidPatternError(`Pattern ${pattern} is not a valid URL`, 'ERR_INVALID_URL') } } /** * Parses a list of route strings into an array of Route objects that contain detailed route information. * * @param {RouteParam[]} allRoutes - An array of route strings to be parsed. Each route string can contain protocols, hostnames, and paths. * @param {ParseRoutesOptions} options - Optional options. * @return {Route[]} An array of parsed Route objects with details such as hostname, path, and protocol. * * @throws {InvalidProtocolError} If provided URL protocol in one of the routes is not `http:` or `https:`. * @throws {InvalidPatternError} If a route contains a query string or infix wildcard which is not allowed. */ export function parseRoutes<Metadata>( allRoutes: RouteParam<Metadata>[], { sortBySpecificity = false }: ParseRoutesOptions = {} ): Route<Metadata>[] { const routes: Route<Metadata>[] = [] for (const rawRoute of allRoutes) { const route = typeof rawRoute === 'string' ? rawRoute : rawRoute.url const metadata = typeof rawRoute === 'string' ? undefined : rawRoute.metadata const hasProtocol = /^[a-z0-9+\-.]+:\/\//i.test(route) let urlInput = route // If route is missing a protocol, give it one so it parses if (!hasProtocol) { urlInput = `https://${urlInput}` } const url = parsePatternUrl(urlInput) let protocol: Protocol | undefined if (hasProtocol) { validateProtocol(url.protocol) protocol = url.protocol } const specificity = sortBySpecificity ? routeSpecificity(url) : undefined const allowHostnamePrefix = url.hostname.startsWith('*') const anyHostname = url.hostname === '*' if (allowHostnamePrefix && !anyHostname) { // Remove leading "*" url.hostname = url.hostname.substring(1) } const allowPathSuffix = url.pathname.endsWith('*') if (allowPathSuffix) { // Remove trailing "*" url.pathname = url.pathname.substring(0, url.pathname.length - 1) } if (url.search) { throw new InvalidPatternError( `Route "${route}" contains a query string. This is not allowed.`, 'ERR_QUERY_STRING' ) } if (url.toString().includes('*') && !anyHostname) { throw new InvalidPatternError( `Route "${route}" contains an infix wildcard. This is not allowed.`, 'ERR_INFIX_WILDCARD' ) } routes.push({ route, metadata, specificity, protocol, wildcardHostnamePrefix: allowHostnamePrefix, hostname: anyHostname ? '' : url.hostname, path: url.pathname, wildcardPathSuffix: allowPathSuffix, }) } if (sortBySpecificity) { // Sort with the highest specificity first routes.sort((a, b) => { Iif (a.specificity === b.specificity) { // If routes are equally specific, sort by the longest route first return b.route.length - a.route.length } else { return b.specificity! - a.specificity! } }) } return routes } |