@@ -122,36 +122,6 @@ function mergeDailyPoints(
122122 . map ( ( [ day , downloads ] ) => ( { day, downloads } ) )
123123}
124124
125- function getIsoWeekStartDateFromWeekKey ( weekKey : string ) : Date | null {
126- const match = / ^ ( \d { 4 } ) - W ( \d { 2 } ) $ / . exec ( weekKey )
127- if ( ! match ) return null
128-
129- const year = Number ( match [ 1 ] )
130- const week = Number ( match [ 2 ] )
131-
132- const januaryFourth = new Date ( Date . UTC ( year , 0 , 4 ) )
133- const januaryFourthIsoDay = januaryFourth . getUTCDay ( ) || 7
134- const weekOneMonday = new Date ( Date . UTC ( year , 0 , 4 - ( januaryFourthIsoDay - 1 ) ) )
135-
136- const weekMonday = new Date ( weekOneMonday )
137- weekMonday . setUTCDate ( weekOneMonday . getUTCDate ( ) + ( week - 1 ) * 7 )
138- return weekMonday
139- }
140-
141- function toIsoWeekKey ( isoDay : string ) : string {
142- const date = new Date ( `${ isoDay } T00:00:00.000Z` )
143- const isoDayOfWeek = date . getUTCDay ( ) || 7
144-
145- const thursday = new Date ( date )
146- thursday . setUTCDate ( date . getUTCDate ( ) + 4 - isoDayOfWeek )
147-
148- const isoYear = thursday . getUTCFullYear ( )
149- const isoYearStart = new Date ( Date . UTC ( isoYear , 0 , 1 ) )
150- const weekNumber = Math . ceil ( ( ( + thursday - + isoYearStart ) / 86400000 + 1 ) / 7 )
151-
152- return `${ isoYear } -W${ String ( weekNumber ) . padStart ( 2 , '0' ) } `
153- }
154-
155125function buildDailyEvolutionFromDaily (
156126 daily : Array < { day : string ; downloads : number } > ,
157127) : DailyDownloadPoint [ ] {
@@ -161,30 +131,38 @@ function buildDailyEvolutionFromDaily(
161131 . map ( item => ( { day : item . day , downloads : item . downloads } ) )
162132}
163133
164- function buildWeeklyEvolutionFromDaily (
134+ function buildRollingWeeklyEvolutionFromDaily (
165135 daily : Array < { day : string ; downloads : number } > ,
136+ rangeStartIso : string ,
166137) : WeeklyDownloadPoint [ ] {
167138 const sorted = daily . slice ( ) . sort ( ( a , b ) => a . day . localeCompare ( b . day ) )
168- const downloadsByWeekKey = new Map < string , number > ( )
139+ const rangeStartDate = parseIsoDateOnly ( rangeStartIso )
140+
141+ const groupedByIndex = new Map < number , number > ( )
169142
170143 for ( const item of sorted ) {
171- const weekKey = toIsoWeekKey ( item . day )
172- downloadsByWeekKey . set ( weekKey , ( downloadsByWeekKey . get ( weekKey ) ?? 0 ) + item . downloads )
173- }
144+ const itemDate = parseIsoDateOnly ( item . day )
145+ const dayOffset = Math . floor ( ( itemDate . getTime ( ) - rangeStartDate . getTime ( ) ) / 86400000 )
146+ if ( dayOffset < 0 ) continue
174147
175- return Array . from ( downloadsByWeekKey . entries ( ) )
176- . sort ( ( [ a ] , [ b ] ) => a . localeCompare ( b ) )
177- . map ( ( [ weekKey , downloads ] ) => {
178- const weekStartDate = getIsoWeekStartDateFromWeekKey ( weekKey )
179- if ( ! weekStartDate ) return { weekKey, downloads, weekStart : '-' , weekEnd : '-' }
148+ const weekIndex = Math . floor ( dayOffset / 7 )
149+ groupedByIndex . set ( weekIndex , ( groupedByIndex . get ( weekIndex ) ?? 0 ) + item . downloads )
150+ }
180151
152+ return Array . from ( groupedByIndex . entries ( ) )
153+ . sort ( ( [ a ] , [ b ] ) => a - b )
154+ . map ( ( [ weekIndex , downloads ] ) => {
155+ const weekStartDate = addDays ( rangeStartDate , weekIndex * 7 )
181156 const weekEndDate = addDays ( weekStartDate , 6 )
182157
158+ const weekStartIso = toIsoDateString ( weekStartDate )
159+ const weekEndIso = toIsoDateString ( weekEndDate )
160+
183161 return {
184- weekKey,
185162 downloads,
186- weekStart : toIsoDateString ( weekStartDate ) ,
187- weekEnd : toIsoDateString ( weekEndDate ) ,
163+ weekKey : `${ weekStartIso } _${ weekEndIso } ` ,
164+ weekStart : weekStartIso ,
165+ weekEnd : weekEndIso ,
188166 }
189167 } )
190168}
@@ -341,6 +319,9 @@ export function useCharts() {
341319 )
342320 } else if ( downloadEvolutionOptions . granularity === 'week' ) {
343321 const weekCount = downloadEvolutionOptions . weeks ?? 52
322+
323+ // Full rolling weeks ending on `end` (yesterday by default)
324+ // Range length is exactly weekCount * 7 days (inclusive)
344325 start = addDays ( end , - ( weekCount * 7 ) + 1 )
345326 } else {
346327 start = addDays ( end , - 30 + 1 )
@@ -362,14 +343,14 @@ export function useCharts() {
362343
363344 const { start, end } = resolveDateRange ( resolvedOptions , resolvedCreatedIso )
364345
365- const sortedDaily = await fetchDailyRangeChunked (
366- resolvedPackageName ,
367- toIsoDateString ( start ) ,
368- toIsoDateString ( end ) ,
369- )
346+ const startIso = toIsoDateString ( start )
347+ const endIso = toIsoDateString ( end )
348+
349+ const sortedDaily = await fetchDailyRangeChunked ( resolvedPackageName , startIso , endIso )
370350
371351 if ( resolvedOptions . granularity === 'day' ) return buildDailyEvolutionFromDaily ( sortedDaily )
372- if ( resolvedOptions . granularity === 'week' ) return buildWeeklyEvolutionFromDaily ( sortedDaily )
352+ if ( resolvedOptions . granularity === 'week' )
353+ return buildRollingWeeklyEvolutionFromDaily ( sortedDaily , startIso )
373354 if ( resolvedOptions . granularity === 'month' ) return buildMonthlyEvolutionFromDaily ( sortedDaily )
374355 return buildYearlyEvolutionFromDaily ( sortedDaily )
375356 }
0 commit comments