@@ -12,15 +12,11 @@ import {
1212 isAppPageRouteModule ,
1313} from '../../../server/route-modules/checks'
1414import { isClientReference } from '../../../lib/client-and-server-references'
15- import {
16- getSegmentParam ,
17- type SegmentParam ,
18- } from '../../../shared/lib/router/utils/get-segment-param'
15+ import { getSegmentParam } from '../../../shared/lib/router/utils/get-segment-param'
1916import {
2017 getLayoutOrPageModule ,
2118 type LoaderTree ,
2219} from '../../../server/lib/app-dir-module'
23- import { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'
2420import type { DynamicParamTypes } from '../../../shared/lib/app-router-types'
2521
2622type GenerateStaticParams = ( options : { params ?: Params } ) => Promise < Params [ ] >
@@ -64,14 +60,7 @@ export type AppSegment = {
6460 paramType : DynamicParamTypes | undefined
6561 filePath : string | undefined
6662 config : AppSegmentConfig | undefined
67- isDynamicSegment : boolean
6863 generateStaticParams : GenerateStaticParams | undefined
69-
70- /**
71- * Whether this segment is a parallel route segment or descends from a
72- * parallel route segment.
73- */
74- isParallelRouteSegment : boolean | undefined
7564}
7665
7766/**
@@ -83,79 +72,57 @@ export type AppSegment = {
8372async function collectAppPageSegments ( routeModule : AppPageRouteModule ) {
8473 // We keep track of unique segments, since with parallel routes, it's possible
8574 // to see the same segment multiple times.
86- const uniqueSegments = new Map < string , AppSegment > ( )
75+ const segments : AppSegment [ ] = [ ]
8776
88- // Queue will store tuples of [loaderTree, currentSegments, isParallelRouteSegment]
89- type QueueItem = [
90- loaderTree : LoaderTree ,
91- currentSegments : AppSegment [ ] ,
92- isParallelRouteSegment : boolean ,
93- ]
94- const queue : QueueItem [ ] = [ [ routeModule . userland . loaderTree , [ ] , false ] ]
77+ // Queue will store loader trees.
78+ const queue : LoaderTree [ ] = [ routeModule . userland . loaderTree ]
9579
9680 while ( queue . length > 0 ) {
97- const [ loaderTree , currentSegments , isParallelRouteSegment ] = queue . shift ( ) !
81+ const loaderTree = queue . shift ( ) !
9882 const [ name , parallelRoutes ] = loaderTree
9983
10084 // Process current node
10185 const { mod : userland , filePath } = await getLayoutOrPageModule ( loaderTree )
10286 const isClientComponent = userland && isClientReference ( userland )
10387
104- const { param : paramName , type : paramType } = getSegmentParam ( name ) ?? { }
88+ const param = getSegmentParam ( name )
10589
10690 const segment : AppSegment = {
10791 name,
108- paramName,
109- paramType,
92+ paramName : param ?. paramName ,
93+ paramType : param ?. paramType ,
11094 filePath,
11195 config : undefined ,
112- isDynamicSegment : ! ! paramName ,
11396 generateStaticParams : undefined ,
114- isParallelRouteSegment,
11597 }
11698
11799 // Only server components can have app segment configurations
118100 if ( ! isClientComponent ) {
119101 attach ( segment , userland , routeModule . definition . pathname )
120102 }
121103
122- // Create a unique key for the segment
123- const segmentKey = getSegmentKey ( segment )
124- if ( ! uniqueSegments . has ( segmentKey ) ) {
125- uniqueSegments . set ( segmentKey , segment )
126- }
127-
128- const updatedSegments = [ ...currentSegments , segment ]
129-
130- // If this is a page segment, we've reached a leaf node
131- if ( name === PAGE_SEGMENT_KEY ) {
132- // Add all segments in the current path, preferring non-parallel segments
133- updatedSegments . forEach ( ( seg ) => {
134- const key = getSegmentKey ( seg )
135- if ( ! uniqueSegments . has ( key ) ) {
136- uniqueSegments . set ( key , seg )
137- }
138- } )
104+ // If this segment doesn't already exist, then add it to the segments array.
105+ // The list of segments is short so we just use a list traversal to check
106+ // for duplicates and spare us needing to maintain the string key.
107+ if (
108+ segments . every (
109+ ( s ) =>
110+ s . name !== segment . name ||
111+ s . paramName !== segment . paramName ||
112+ s . paramType !== segment . paramType ||
113+ s . filePath !== segment . filePath
114+ )
115+ ) {
116+ segments . push ( segment )
139117 }
140118
141119 // Add all parallel routes to the queue
142- for ( const parallelRouteKey in parallelRoutes ) {
143- const parallelRoute = parallelRoutes [ parallelRouteKey ]
144- queue . push ( [
145- parallelRoute ,
146- updatedSegments ,
147- // A parallel route segment is one that descends from a segment that is
148- // not children or descends from a parallel route segment.
149- isParallelRouteSegment || parallelRouteKey !== 'children' ,
150- ] )
120+ for ( const parallelRoute of Object . values ( parallelRoutes ) ) {
121+ queue . push ( parallelRoute )
151122 }
152123 }
153124
154- return Array . from ( uniqueSegments . values ( ) )
155- }
156-
157- function getSegmentKey ( segment : AppSegment ) {
158- return `${ segment . name } -${ segment . filePath ?? '' } -${ segment . paramName ?? '' } -${ segment . isParallelRouteSegment ? 'pr' : 'np' } `
125+ return segments
159126}
160127
161128/**
@@ -175,17 +142,15 @@ function collectAppRouteSegments(
175142
176143 // Generate all the segments.
177144 const segments : AppSegment [ ] = parts . map ( ( name ) => {
178- const { param : paramName , type : paramType } = getSegmentParam ( name ) ?? { }
145+ const param = getSegmentParam ( name )
179146
180147 return {
181148 name,
182- paramName,
183- paramType,
149+ paramName : param ?. paramName ,
150+ paramType : param ?. paramType ,
184151 filePath : undefined ,
185- isDynamicSegment : ! ! paramName ,
186152 config : undefined ,
187153 generateStaticParams : undefined ,
188- isParallelRouteSegment : undefined ,
189154 } satisfies AppSegment
190155 } )
191156
@@ -222,48 +187,3 @@ export function collectSegments(
222187 'Expected a route module to be one of app route or page'
223188 )
224189}
225-
226- /**
227- * Collects the segment params for a given app page route module. This is
228- * a variant of the `collectSegments` function that only collects the segment
229- * params without importing anything.
230- *
231- * @param routeModule the app page route module
232- * @returns the segment params for the app page route module
233- */
234- export function collectSegmentParams (
235- routeModule : AppPageRouteModule
236- ) : readonly SegmentParam [ ] {
237- const uniqueSegments = new Map < string , SegmentParam > ( )
238-
239- // Queue will store tuples of [loaderTree, isParallelRouteSegment]
240- type QueueItem = [ loaderTree : LoaderTree , isParallelRouteSegment : boolean ]
241- const queue : QueueItem [ ] = [ [ routeModule . userland . loaderTree , false ] ]
242-
243- while ( queue . length > 0 ) {
244- const [ loaderTree , isParallelRouteSegment ] = queue . shift ( ) !
245- const [ name , parallelRoutes ] = loaderTree
246-
247- // Handle this segment (if it's a dynamic segment param).
248- const segmentParam = getSegmentParam ( name )
249- if ( segmentParam ) {
250- const key = `${ name } -${ segmentParam . param } -${ isParallelRouteSegment ? 'pr' : 'np' } `
251- if ( ! uniqueSegments . has ( key ) ) {
252- uniqueSegments . set ( key , segmentParam )
253- }
254- }
255-
256- // Add all of this segment's parallel routes to the queue.
257- for ( const parallelRouteKey in parallelRoutes ) {
258- const parallelRoute = parallelRoutes [ parallelRouteKey ]
259- queue . push ( [
260- parallelRoute ,
261- // A parallel route segment is one that descends from a segment that is
262- // not children or descends from a parallel route segment.
263- isParallelRouteSegment || parallelRouteKey !== 'children' ,
264- ] )
265- }
266- }
267-
268- return Array . from ( uniqueSegments . values ( ) )
269- }
0 commit comments