UNPKG

next

Version:

The React Framework

128 lines (127 loc) 5.31 kB
/** * * Shared logic on client and server for creating a dynamic param value. * * This code needs to be shared with the client so it can extract dynamic route * params from the URL without a server request. * * Because everything in this module is sent to the client, we should aim to * keep this code as simple as possible. The special case handling for catchall * and optional is, alas, unfortunate. */ export function getDynamicParam(params, segmentKey, dynamicParamType, pagePath, fallbackRouteParams) { let value = params[segmentKey]; if (fallbackRouteParams && fallbackRouteParams.has(segmentKey)) { value = fallbackRouteParams.get(segmentKey); } else if (Array.isArray(value)) { value = value.map((i)=>encodeURIComponent(i)); } else if (typeof value === 'string') { value = encodeURIComponent(value); } if (!value) { const isCatchall = dynamicParamType === 'c'; const isOptionalCatchall = dynamicParamType === 'oc'; if (isCatchall || isOptionalCatchall) { // handle the case where an optional catchall does not have a value, // e.g. `/dashboard/[[...slug]]` when requesting `/dashboard` if (isOptionalCatchall) { return { param: segmentKey, value: null, type: dynamicParamType, treeSegment: [ segmentKey, '', dynamicParamType ] }; } // handle the case where a catchall or optional catchall does not have a value, // e.g. `/foo/bar/hello` and `@slot/[...catchall]` or `@slot/[[...catchall]]` is matched value = pagePath.split('/')// remove the first empty string .slice(1)// replace any dynamic params with the actual values .flatMap((pathSegment)=>{ const param = parseParameter(pathSegment); var _params_param_key; // if the segment matches a param, return the param value // otherwise, it's a static segment, so just return that return (_params_param_key = params[param.key]) != null ? _params_param_key : param.key; }); return { param: segmentKey, value, type: dynamicParamType, // This value always has to be a string. treeSegment: [ segmentKey, value.join('/'), dynamicParamType ] }; } } return { param: segmentKey, // The value that is passed to user code. value: value, // The value that is rendered in the router tree. treeSegment: [ segmentKey, Array.isArray(value) ? value.join('/') : value, dynamicParamType ], type: dynamicParamType }; } /** * Regular expression pattern used to match route parameters. * Matches both single parameters and parameter groups. * Examples: * - `[[...slug]]` matches parameter group with key 'slug', repeat: true, optional: true * - `[...slug]` matches parameter group with key 'slug', repeat: true, optional: false * - `[[foo]]` matches parameter with key 'foo', repeat: false, optional: true * - `[bar]` matches parameter with key 'bar', repeat: false, optional: false */ export const PARAMETER_PATTERN = /^([^[]*)\[((?:\[[^\]]*\])|[^\]]+)\](.*)$/; /** * Parses a given parameter from a route to a data structure that can be used * to generate the parametrized route. * Examples: * - `[[...slug]]` -> `{ key: 'slug', repeat: true, optional: true }` * - `[...slug]` -> `{ key: 'slug', repeat: true, optional: false }` * - `[[foo]]` -> `{ key: 'foo', repeat: false, optional: true }` * - `[bar]` -> `{ key: 'bar', repeat: false, optional: false }` * - `fizz` -> `{ key: 'fizz', repeat: false, optional: false }` * @param param - The parameter to parse. * @returns The parsed parameter as a data structure. */ export function parseParameter(param) { const match = param.match(PARAMETER_PATTERN); if (!match) { return parseMatchedParameter(param); } return parseMatchedParameter(match[2]); } /** * Parses a matched parameter from the PARAMETER_PATTERN regex to a data structure that can be used * to generate the parametrized route. * Examples: * - `[...slug]` -> `{ key: 'slug', repeat: true, optional: true }` * - `...slug` -> `{ key: 'slug', repeat: true, optional: false }` * - `[foo]` -> `{ key: 'foo', repeat: false, optional: true }` * - `bar` -> `{ key: 'bar', repeat: false, optional: false }` * @param param - The matched parameter to parse. * @returns The parsed parameter as a data structure. */ export function parseMatchedParameter(param) { const optional = param.startsWith('[') && param.endsWith(']'); if (optional) { param = param.slice(1, -1); } const repeat = param.startsWith('...'); if (repeat) { param = param.slice(3); } return { key: param, repeat, optional }; } //# sourceMappingURL=get-dynamic-param.js.map