one
Version:
One is a new React Framework that makes Vite serve both native and web.
158 lines (136 loc) • 4.72 kB
text/typescript
/**
* This file exports things that will be used to modify the forked code in `getPathFromState.ts`.
*
* The purpose of keeping things in this separated file is to keep changes to the copied code as little as possible, making merging upstream updates easier.
*/
import type { Route } from '@react-navigation/core'
import { matchDeepDynamicRouteName, matchDynamicName, matchGroupName } from '../router/matchers'
import { getParamName } from './_shared'
export type AdditionalOptions = {
preserveDynamicRoutes?: boolean
preserveGroups?: boolean
shouldEncodeURISegment?: boolean
}
export type ConfigItemMods = {
// Used as fallback for groups
initialRouteName?: string
}
export function getPathWithConventionsCollapsed({
pattern,
route,
params,
preserveGroups,
preserveDynamicRoutes,
shouldEncodeURISegment = true,
initialRouteName,
}: AdditionalOptions & {
pattern: string
route: Route<any>
params: Record<string, any>
initialRouteName?: string
}) {
const segments = pattern.split('/')
return segments
.map((p, i) => {
const name = getParamName(p)
// We don't know what to show for wildcard patterns
// Showing the route name seems ok, though whatever we show here will be incorrect
// Since the page doesn't actually exist
if (p.startsWith('*')) {
if (preserveDynamicRoutes) {
if (name === 'not-found') {
return '+not-found'
}
return `[...${name}]`
}
if (params[name]) {
if (Array.isArray(params[name])) {
return params[name].join('/')
}
return params[name]
}
if (route.name.startsWith('[') && route.name.endsWith(']')) {
return ''
}
if (i === 0) {
// This can occur when a wildcard matches all routes and the given path was `/`.
return route
}
if (p === '*not-found') {
return ''
}
// remove existing segments from route.path and return it
// this is used for nested wildcard routes. Without this, the path would add
// all nested segments to the beginning of the wildcard route.
return route.name
?.split('/')
.slice(i + 1)
.join('/')
}
// If the path has a pattern for a param, put the param in the path
if (p.startsWith(':')) {
if (preserveDynamicRoutes) {
return `[${name}]`
}
// Optional params without value assigned in route.params should be ignored
const value = params[name]
if (value === undefined && p.endsWith('?')) {
return
}
// return params[name]
return (shouldEncodeURISegment ? encodeURISegment(value) : value) ?? 'undefined'
}
if (!preserveGroups && matchGroupName(p) != null) {
// When the last part is a group it could be a shared URL
// if the route has an initialRouteName defined, then we should
// use that as the component path as we can assume it will be shown.
if (segments.length - 1 === i) {
if (initialRouteName) {
// Return an empty string if the init route is ambiguous.
if (segmentMatchesConvention(initialRouteName)) {
return ''
}
return shouldEncodeURISegment
? encodeURIComponentPreservingBrackets(initialRouteName)
: initialRouteName
}
}
return ''
}
return shouldEncodeURISegment ? encodeURIComponentPreservingBrackets(p) : p
})
.map((v) => v ?? '')
.join('/')
}
function encodeURIComponentPreservingBrackets(str: string) {
return encodeURIComponent(str).replace(/%5B/g, '[').replace(/%5D/g, ']')
}
export function appendBaseUrl(
path: string,
baseUrl: string | undefined = process.env.EXPO_BASE_URL
) {
if (process.env.NODE_ENV !== 'development') {
if (baseUrl) {
return `/${baseUrl.replace(/^\/+/, '').replace(/\/$/, '')}${path}`
}
}
return path
}
function segmentMatchesConvention(segment: string): boolean {
return (
segment === 'index' ||
matchDynamicName(segment) != null ||
matchGroupName(segment) != null ||
matchDeepDynamicRouteName(segment) != null
)
}
function encodeURISegment(str: string, { preserveBrackets = false } = {}) {
// Valid characters according to
// https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 (see pchar definition)
str = String(str).replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]/g, (char) => encodeURIComponent(char))
if (preserveBrackets) {
// Preserve brackets
str = str.replace(/%5B/g, '[').replace(/%5D/g, ']')
}
return str
}