UNPKG

next

Version:

The React Framework

103 lines (102 loc) 5.62 kB
import { collectFallbackRouteParams } from '../../build/segment-config/app/app-segments'; import { InvariantError } from '../../shared/lib/invariant-error'; import { getRouteMatcher } from '../../shared/lib/router/utils/route-matcher'; import { getRouteRegex } from '../../shared/lib/router/utils/route-regex'; import { dynamicParamTypes } from '../app-render/get-short-dynamic-param-type'; function getParamKeys(page) { const pattern = getRouteRegex(page); const matcher = getRouteMatcher(pattern); // Get the default list of allowed params. return Object.keys(matcher(page)); } /** * Creates an opaque fallback route params object from the fallback route params. * * @param fallbackRouteParams the fallback route params * @returns the opaque fallback route params */ export function createOpaqueFallbackRouteParams(fallbackRouteParams) { // If there are no fallback route params, we can return early. if (fallbackRouteParams.length === 0) return null; // As we're creating unique keys for each of the dynamic route params, we only // need to generate a unique ID once per request because each of the keys will // be also be unique. const uniqueID = Math.random().toString(16).slice(2); const keys = new Map(); // Generate a unique key for the fallback route param, if this key is found // in the static output, it represents a bug in cache components. for (const { paramName, paramType } of fallbackRouteParams){ keys.set(paramName, [ `%%drp:${paramName}:${uniqueID}%%`, dynamicParamTypes[paramType] ]); } return keys; } /** * Gets the fallback route params for a given page. This is an expensive * operation because it requires parsing the loader tree to extract the fallback * route params. * * @param page the page * @param routeModule the route module * @returns the opaque fallback route params */ export function getFallbackRouteParams(page, routeModule) { // First, get the fallback route params based on the provided page. const unknownParamKeys = new Set(getParamKeys(page)); // Needed when processing fallback route params for catchall routes in // parallel segments, derive from pathname. This is similar to // getDynamicParam's pagePath parsing logic. const pathSegments = page.split('/').filter(Boolean); const collected = collectFallbackRouteParams(routeModule); // Then, we have to get the fallback route params from the segments that are // associated with parallel route segments. const fallbackRouteParams = []; for (const fallbackRouteParam of collected){ if (fallbackRouteParam.isParallelRouteParam) { // Try to see if we can resolve this parameter from the page that was // passed in. if (unknownParamKeys.has(fallbackRouteParam.paramName)) { continue; } if (fallbackRouteParam.paramType === 'optional-catchall' || fallbackRouteParam.paramType === 'catchall') { // If there are any fallback route segments then we can't use the // pathname to derive the value because it's not complete. We can // make this assumption because the routes are always resolved left // to right and the catchall is always the last segment, so any // route parameters that are unknown will always contribute to the // pathname and therefore the catchall param too. if (collected.some((param)=>!param.isParallelRouteParam && unknownParamKeys.has(param.paramName))) { fallbackRouteParams.push(fallbackRouteParam); continue; } if (pathSegments.length === 0 && fallbackRouteParam.paramType !== 'optional-catchall') { // We shouldn't be able to match a catchall segment without any path // segments if it's not an optional catchall. throw Object.defineProperty(new InvariantError(`Unexpected empty path segments match for a pathname "${page}" with param "${fallbackRouteParam.paramName}" of type "${fallbackRouteParam.paramType}"`), "__NEXT_ERROR_CODE", { value: "E792", enumerable: false, configurable: true }); } // The path segments are not empty, and the segments didn't contain any // unknown params, so we know that this particular fallback route param // route param is not actually unknown, and is known. We can skip adding // it to the fallback route params. } else { // This is some other type of route param that shouldn't get resolved // statically. throw Object.defineProperty(new InvariantError(`Unexpected match for a pathname "${page}" with a param "${fallbackRouteParam.paramName}" of type "${fallbackRouteParam.paramType}"`), "__NEXT_ERROR_CODE", { value: "E791", enumerable: false, configurable: true }); } } else if (unknownParamKeys.has(fallbackRouteParam.paramName)) { // As this is a non-parallel route segment, and it exists in the unknown // param keys, we know it's a fallback route param. fallbackRouteParams.push(fallbackRouteParam); } } return createOpaqueFallbackRouteParams(fallbackRouteParams); } //# sourceMappingURL=fallback-params.js.map