next.js/packages/next/src/shared/lib/router/utils/get-segment-param.tsx
get-segment-param.tsx103 lines2.6 KB
import { INTERCEPTION_ROUTE_MARKERS } from './interception-routes'
import type { DynamicParamTypes } from '../../app-router-types'

export type SegmentParam = {
  paramName: string
  paramType: DynamicParamTypes
}

/**
 * Parse dynamic route segment to type of parameter
 */
export function getSegmentParam(segment: string): SegmentParam | null {
  const interceptionMarker = INTERCEPTION_ROUTE_MARKERS.find((marker) =>
    segment.startsWith(marker)
  )

  // if an interception marker is part of the path segment, we need to jump ahead
  // to the relevant portion for param parsing
  if (interceptionMarker) {
    segment = segment.slice(interceptionMarker.length)
  }

  if (segment.startsWith('[[...') && segment.endsWith(']]')) {
    return {
      // TODO-APP: Optional catchall does not currently work with parallel routes,
      // so for now aren't handling a potential interception marker.
      paramType: 'optional-catchall',
      paramName: segment.slice(5, -2),
    }
  }

  if (segment.startsWith('[...') && segment.endsWith(']')) {
    return {
      paramType: interceptionMarker
        ? `catchall-intercepted-${interceptionMarker}`
        : 'catchall',
      paramName: segment.slice(4, -1),
    }
  }

  if (segment.startsWith('[') && segment.endsWith(']')) {
    return {
      paramType: interceptionMarker
        ? `dynamic-intercepted-${interceptionMarker}`
        : 'dynamic',
      paramName: segment.slice(1, -1),
    }
  }

  return null
}

export function isCatchAll(
  type: DynamicParamTypes
): type is
  | 'catchall'
  | 'catchall-intercepted-(..)(..)'
  | 'catchall-intercepted-(.)'
  | 'catchall-intercepted-(..)'
  | 'catchall-intercepted-(...)'
  | 'optional-catchall' {
  return (
    type === 'catchall' ||
    type === 'catchall-intercepted-(..)(..)' ||
    type === 'catchall-intercepted-(.)' ||
    type === 'catchall-intercepted-(..)' ||
    type === 'catchall-intercepted-(...)' ||
    type === 'optional-catchall'
  )
}

export function getParamProperties(paramType: DynamicParamTypes): {
  repeat: boolean
  optional: boolean
} {
  let repeat = false
  let optional = false

  switch (paramType) {
    case 'catchall':
    case 'catchall-intercepted-(..)(..)':
    case 'catchall-intercepted-(.)':
    case 'catchall-intercepted-(..)':
    case 'catchall-intercepted-(...)':
      repeat = true
      break
    case 'optional-catchall':
      repeat = true
      optional = true
      break
    case 'dynamic':
    case 'dynamic-intercepted-(..)(..)':
    case 'dynamic-intercepted-(.)':
    case 'dynamic-intercepted-(..)':
    case 'dynamic-intercepted-(...)':
      break
    default:
      paramType satisfies never
  }

  return { repeat, optional }
}
Quest for Codev2.0.0
/
SIGN IN