@@ -96,6 +96,28 @@ const buildCSMNodeWithPullRequest = (csmNode: CSMNode, pr: PullRequest): CSMNode
9696 } ;
9797} ;
9898
99+ /** Builds a Pull Request dictionary indexed by merge commit SHA. */
100+ const buildPRDict = ( pullRequests : Array < PullRequest > ) : PullRequestDict => {
101+ return pullRequests . reduce (
102+ ( dict , pr ) => dict . set ( `${ pr . detail . data . merge_commit_sha } ` , pr ) ,
103+ new Map < string , PullRequest > ( ) as PullRequestDict
104+ ) ;
105+ } ;
106+
107+ /** Builds CSM nodes from commit nodes with PR integration. */
108+ const buildCSMNodesWithPR = (
109+ commitNodes : CommitNode [ ] ,
110+ commitDict : CommitDict ,
111+ stemDict : StemDict ,
112+ prDict : PullRequestDict
113+ ) : CSMNode [ ] => {
114+ return commitNodes . map ( ( commitNode ) => {
115+ const csmNode = buildCSMNode ( commitNode , commitDict , stemDict ) ;
116+ const pr = prDict . get ( csmNode . base . commit . id ) ;
117+ return pr ? buildCSMNodeWithPullRequest ( csmNode , pr ) : csmNode ;
118+ } ) ;
119+ } ;
120+
99121/**
100122 * Builds a CSM (Commit Summary Model) dictionary.
101123 * Creates CSM nodes for each commit in the base branch,
@@ -126,18 +148,62 @@ export const buildCSMDict = (
126148 // return {};
127149 }
128150
129- const prDictByMergedCommitSha = pullRequests . reduce (
130- ( dict , pr ) => dict . set ( `${ pr . detail . data . merge_commit_sha } ` , pr ) ,
131- new Map < string , PullRequest > ( ) as PullRequestDict
132- ) ;
151+ const prDict = buildPRDict ( pullRequests ) ;
152+ const csmNodes = buildCSMNodesWithPR ( masterStem . nodes , commitDict , stemDict , prDict ) ;
133153
134- const csmDict : CSMDictionary = { } ;
135- const stemNodes = masterStem . nodes ; // start on latest-node
136- csmDict [ baseBranchName ] = stemNodes . map ( ( commitNode ) => {
137- const csmNode = buildCSMNode ( commitNode , commitDict , stemDict ) ;
138- const pr = prDictByMergedCommitSha . get ( csmNode . base . commit . id ) ;
139- return pr ? buildCSMNodeWithPullRequest ( csmNode , pr ) : csmNode ;
140- } ) ;
154+ return {
155+ [ baseBranchName ] : csmNodes ,
156+ } ;
157+ } ;
158+
159+ /**
160+ * Builds a paginated CSM dictionary.
161+ * Creates CSM nodes for a specific range of commits in the base branch,
162+ * enabling efficient lazy loading for large repositories.
163+ */
164+ export const buildPaginatedCSMDict = (
165+ commitDict : CommitDict ,
166+ stemDict : StemDict ,
167+ baseBranchName : string ,
168+ perPage : number ,
169+ lastCommitId ?: string ,
170+ pullRequests : Array < PullRequest > = [ ]
171+ ) : CSMDictionary => {
172+ // Validate perPage
173+ if ( perPage <= 0 ) {
174+ throw new Error ( "perPage must be greater than 0" ) ;
175+ }
176+
177+ // Validate stemDict
178+ if ( stemDict . size === 0 ) {
179+ throw new Error ( "no stem" ) ;
180+ }
181+
182+ // Get base branch stem
183+ const baseStem = stemDict . get ( baseBranchName ) ;
184+ if ( ! baseStem ) {
185+ throw new Error ( "no master-stem" ) ;
186+ }
141187
142- return csmDict ;
188+ // Determine start index based on cursor
189+ let startIndex = 0 ;
190+ if ( lastCommitId ) {
191+ const lastCommitIndex = baseStem . nodes . findIndex ( ( node ) => node . commit . id === lastCommitId ) ;
192+ if ( lastCommitIndex === - 1 ) {
193+ throw new Error ( "Invalid lastCommitId" ) ;
194+ }
195+ startIndex = lastCommitIndex + 1 ;
196+ }
197+
198+ // Calculate end index and extract page nodes
199+ const endIndex = Math . min ( startIndex + perPage , baseStem . nodes . length ) ;
200+ const pageNodes = baseStem . nodes . slice ( startIndex , endIndex ) ;
201+
202+ // Build CSM nodes with PR integration
203+ const prDict = buildPRDict ( pullRequests ) ;
204+ const csmNodes = buildCSMNodesWithPR ( pageNodes , commitDict , stemDict , prDict ) ;
205+
206+ return {
207+ [ baseBranchName ] : csmNodes ,
208+ } ;
143209} ;
0 commit comments