3
3
4
4
import { mkdir , readFile , writeFile } from 'node:fs/promises' ;
5
5
import { dirname , join } from 'node:path' ;
6
- import * as semver from 'semver' ;
7
6
8
7
interface NpmDownloadResponse {
9
8
package : string ;
@@ -32,22 +31,6 @@ async function fetchPackageStats(packageName: string): Promise<NpmDownloadRespon
32
31
return response . json ( ) as Promise < NpmDownloadResponse > ;
33
32
}
34
33
35
- function aggregateByMajorVersion ( downloads : Record < string , number > ) : Record < string , number > {
36
- const majorVersions : Record < string , number > = { } ;
37
-
38
- for ( const [ version , count ] of Object . entries ( downloads ) ) {
39
- const major = semver . major ( version ) ;
40
- const majorKey = major . toString ( ) ;
41
-
42
- if ( ! majorVersions [ majorKey ] ) {
43
- majorVersions [ majorKey ] = 0 ;
44
- }
45
- majorVersions [ majorKey ] += count ;
46
- }
47
-
48
- return majorVersions ;
49
- }
50
-
51
34
async function readExistingData ( filePath : string ) : Promise < HistoricalData | null > {
52
35
try {
53
36
const content = await readFile ( filePath , 'utf-8' ) ;
@@ -70,8 +53,8 @@ async function updateHistoricalData(
70
53
if ( ! existingData ) {
71
54
// Create new data structure
72
55
const downloads : Record < string , number [ ] > = { } ;
73
- for ( const [ major , count ] of Object . entries ( newDownloads ) ) {
74
- downloads [ major ] = [ count ] ;
56
+ for ( const [ version , count ] of Object . entries ( newDownloads ) ) {
57
+ downloads [ version ] = [ count ] ;
75
58
}
76
59
77
60
return {
@@ -89,18 +72,18 @@ async function updateHistoricalData(
89
72
} ;
90
73
91
74
// Add new download counts
92
- for ( const [ major , count ] of Object . entries ( newDownloads ) ) {
93
- if ( ! updatedData . downloads [ major ] ) {
94
- // New major version - backfill with zeros for historical timestamps
95
- updatedData . downloads [ major ] = new Array ( existingData . timestamps . length ) . fill ( 0 ) ;
75
+ for ( const [ version , count ] of Object . entries ( newDownloads ) ) {
76
+ if ( ! updatedData . downloads [ version ] ) {
77
+ // New version - backfill with zeros for historical timestamps
78
+ updatedData . downloads [ version ] = new Array ( existingData . timestamps . length ) . fill ( 0 ) ;
96
79
}
97
- updatedData . downloads [ major ] . push ( count ) ;
80
+ updatedData . downloads [ version ] . push ( count ) ;
98
81
}
99
82
100
- // Ensure all existing major versions have a new entry (fill with 0 if no downloads)
101
- for ( const major of Object . keys ( existingData . downloads ) ) {
102
- if ( ! newDownloads [ major ] ) {
103
- updatedData . downloads [ major ] . push ( 0 ) ;
83
+ // Ensure all existing versions have a new entry (fill with 0 if no downloads)
84
+ for ( const version of Object . keys ( existingData . downloads ) ) {
85
+ if ( ! newDownloads [ version ] ) {
86
+ updatedData . downloads [ version ] . push ( 0 ) ;
104
87
}
105
88
}
106
89
@@ -112,8 +95,15 @@ async function processPackage(packageName: string): Promise<void> {
112
95
// Fetch current stats
113
96
const stats = await fetchPackageStats ( packageName ) ;
114
97
115
- // Aggregate by major version
116
- const aggregatedDownloads = aggregateByMajorVersion ( stats . downloads ) ;
98
+ // Check if package has any download statistics
99
+ if ( ! stats . downloads || Object . keys ( stats . downloads ) . length === 0 ) {
100
+ throw new Error (
101
+ `Package ${ packageName } has no download statistics - it may not exist or have no downloads` ,
102
+ ) ;
103
+ }
104
+
105
+ // Use all versions without aggregation
106
+ const allVersionDownloads = stats . downloads ;
117
107
118
108
// Determine file path
119
109
const dataDir = join ( process . cwd ( ) , 'data' , 'npm-versions' ) ;
@@ -126,15 +116,15 @@ async function processPackage(packageName: string): Promise<void> {
126
116
const existingData = await readExistingData ( filePath ) ;
127
117
128
118
// Update historical data
129
- const updatedData = await updateHistoricalData ( packageName , aggregatedDownloads , existingData ) ;
119
+ const updatedData = await updateHistoricalData ( packageName , allVersionDownloads , existingData ) ;
130
120
131
121
// Write back to file
132
122
await writeFile ( filePath , JSON . stringify ( updatedData , null , 2 ) ) ;
133
123
134
124
console . log ( `✅ Updated stats for ${ packageName } ` ) ;
135
- console . log ( ` Major versions : ${ Object . keys ( aggregatedDownloads ) . join ( ', ' ) } ` ) ;
125
+ console . log ( ` Versions : ${ Object . keys ( allVersionDownloads ) . join ( ', ' ) } ` ) ;
136
126
console . log (
137
- ` Total downloads: ${ Object . values ( aggregatedDownloads ) . reduce ( ( a , b ) => a + b , 0 ) } ` ,
127
+ ` Total downloads: ${ Object . values ( allVersionDownloads ) . reduce ( ( a , b ) => a + b , 0 ) } ` ,
138
128
) ;
139
129
} catch ( error ) {
140
130
console . error ( `❌ Failed to process ${ packageName } :` , error ) ;
0 commit comments