next
Version:
The React Framework
103 lines (102 loc) • 5.62 kB
JavaScript
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