Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 66 additions & 46 deletions packages/router-core/src/new-process-route-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,17 @@ type ExtendedSegmentKind =
| typeof SEGMENT_TYPE_INDEX
| typeof SEGMENT_TYPE_PATHLESS

const PARAM_W_CURLY_BRACES_RE =
/^([^{]*)\{\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/ // prefix{$paramName}suffix
const OPTIONAL_PARAM_W_CURLY_BRACES_RE =
/^([^{]*)\{-\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/ // prefix{-$paramName}suffix
const WILDCARD_W_CURLY_BRACES_RE = /^([^{]*)\{\$\}([^}]*)$/ // prefix{$}suffix
function getOpenAndCloseBraces(
part: string,
): [openBrace: number, closeBrace: number] | null {
const openBrace = part.indexOf('{')
if (openBrace === -1) return null
const closeBrace = part.indexOf('}', openBrace)
if (closeBrace === -1) return null
const afterOpen = openBrace + 1
if (afterOpen >= part.length) return null
return [openBrace, closeBrace]
}

type ParsedSegment = Uint16Array & {
/** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */
Expand Down Expand Up @@ -110,47 +116,61 @@ export function parseSegment(
return output as ParsedSegment
}

const wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE)
if (wildcardBracesMatch) {
const prefix = wildcardBracesMatch[1]!
const pLength = prefix.length
output[0] = SEGMENT_TYPE_WILDCARD
output[1] = start + pLength
output[2] = start + pLength + 1 // skip '{'
output[3] = start + pLength + 2 // '$'
output[4] = start + pLength + 3 // skip '}'
output[5] = path.length
return output as ParsedSegment
}

const optionalParamBracesMatch = part.match(OPTIONAL_PARAM_W_CURLY_BRACES_RE)
if (optionalParamBracesMatch) {
const prefix = optionalParamBracesMatch[1]!
const paramName = optionalParamBracesMatch[2]!
const suffix = optionalParamBracesMatch[3]!
const pLength = prefix.length
output[0] = SEGMENT_TYPE_OPTIONAL_PARAM
output[1] = start + pLength
output[2] = start + pLength + 3 // skip '{-$'
output[3] = start + pLength + 3 + paramName.length
output[4] = end - suffix.length
output[5] = end
return output as ParsedSegment
}

const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE)
if (paramBracesMatch) {
const prefix = paramBracesMatch[1]!
const paramName = paramBracesMatch[2]!
const suffix = paramBracesMatch[3]!
const pLength = prefix.length
output[0] = SEGMENT_TYPE_PARAM
output[1] = start + pLength
output[2] = start + pLength + 2 // skip '{$'
output[3] = start + pLength + 2 + paramName.length
output[4] = end - suffix.length
output[5] = end
return output as ParsedSegment
const braces = getOpenAndCloseBraces(part)
if (braces) {
const [openBrace, closeBrace] = braces
const firstChar = part.charCodeAt(openBrace + 1)

// Check for {-$...} (optional param)
// prefix{-$paramName}suffix
// /^([^{]*)\{-\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/
if (firstChar === 45) {
// '-'
if (
openBrace + 2 < part.length &&
part.charCodeAt(openBrace + 2) === 36 // '$'
) {
const paramStart = openBrace + 3
const paramEnd = closeBrace
// Validate param name exists
if (paramStart < paramEnd) {
output[0] = SEGMENT_TYPE_OPTIONAL_PARAM
output[1] = start + openBrace
output[2] = start + paramStart
output[3] = start + paramEnd
output[4] = start + closeBrace + 1
output[5] = end
return output as ParsedSegment
}
}
} else if (firstChar === 36) {
// '$'
const dollarPos = openBrace + 1
const afterDollar = openBrace + 2
// Check for {$} (wildcard)
if (afterDollar === closeBrace) {
// For wildcard, value should be '$' (from dollarPos to afterDollar)
// prefix{$}suffix
// /^([^{]*)\{\$\}([^}]*)$/
output[0] = SEGMENT_TYPE_WILDCARD
output[1] = start + openBrace
output[2] = start + dollarPos
output[3] = start + afterDollar
output[4] = start + closeBrace + 1
output[5] = path.length
return output as ParsedSegment
}
// Regular param {$paramName} - value is the param name (after $)
// prefix{$paramName}suffix
// /^([^{]*)\{\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/
output[0] = SEGMENT_TYPE_PARAM
output[1] = start + openBrace
output[2] = start + afterDollar
output[3] = start + closeBrace
output[4] = start + closeBrace + 1
output[5] = end
return output as ParsedSegment
}
}

// fallback to static pathname (should never happen)
Expand Down
Loading