@@ -34,6 +34,47 @@ function fetchUrl(url) {
3434 } ) ;
3535}
3636
37+ /**
38+ * Parse version string into comparable parts
39+ * Returns object with major, minor, patch, and prerelease info
40+ */
41+ function parseVersion ( versionString ) {
42+ const parts = versionString . match ( / ^ ( \d + ) \. ( \d + ) \. ( \d + ) (?: - ( .+ ) ) ? $ / ) ;
43+ if ( ! parts ) return null ;
44+
45+ return {
46+ major : parseInt ( parts [ 1 ] ) ,
47+ minor : parseInt ( parts [ 2 ] ) ,
48+ patch : parseInt ( parts [ 3 ] ) ,
49+ prerelease : parts [ 4 ] || null
50+ } ;
51+ }
52+
53+ /**
54+ * Compare two version strings
55+ * Returns: -1 if a < b, 0 if equal, 1 if a > b
56+ */
57+ function compareVersions ( versionA , versionB ) {
58+ const a = parseVersion ( versionA ) ;
59+ const b = parseVersion ( versionB ) ;
60+
61+ if ( ! a || ! b ) return 0 ;
62+
63+ // Compare major, minor, patch
64+ if ( a . major !== b . major ) return a . major - b . major ;
65+ if ( a . minor !== b . minor ) return a . minor - b . minor ;
66+ if ( a . patch !== b . patch ) return a . patch - b . patch ;
67+
68+ // If versions are equal up to patch, handle prerelease
69+ // Stable versions (no prerelease) come AFTER prereleases
70+ if ( ! a . prerelease && ! b . prerelease ) return 0 ;
71+ if ( ! a . prerelease ) return 1 ; // a is stable, b is prerelease
72+ if ( ! b . prerelease ) return - 1 ; // a is prerelease, b is stable
73+
74+ // Both are prereleases, compare prerelease strings
75+ return a . prerelease . localeCompare ( b . prerelease ) ;
76+ }
77+
3778function parseChangelog ( markdown , type ) {
3879 const lines = markdown . split ( '\n' ) ;
3980 const versions = [ ] ;
@@ -195,12 +236,20 @@ async function generateChangelog() {
195236 function limitStableWithDev ( versions , maxStable ) {
196237 const stable = versions
197238 . filter ( v => ! v . isDev )
198- . sort ( ( a , b ) => new Date ( b . date ) - new Date ( a . date ) )
239+ . sort ( ( a , b ) => {
240+ const dateCompare = new Date ( b . date ) - new Date ( a . date ) ;
241+ if ( dateCompare !== 0 ) return dateCompare ;
242+ return compareVersions ( b . version , a . version ) ;
243+ } )
199244 . slice ( 0 , maxStable ) ;
200245
201246 const dev = versions
202247 . filter ( v => v . isDev )
203- . sort ( ( a , b ) => new Date ( b . date ) - new Date ( a . date ) ) ;
248+ . sort ( ( a , b ) => {
249+ const dateCompare = new Date ( b . date ) - new Date ( a . date ) ;
250+ if ( dateCompare !== 0 ) return dateCompare ;
251+ return compareVersions ( b . version , a . version ) ;
252+ } ) ;
204253
205254 return [ ...stable , ...dev ] ;
206255 }
@@ -209,7 +258,14 @@ async function generateChangelog() {
209258 const limitedPatchesVersions = limitStableWithDev ( patchesVersions , MAX_PATCHES_RELEASES ) ;
210259
211260 const allVersions = [ ...limitedManagerVersions , ...limitedPatchesVersions ]
212- . sort ( ( a , b ) => new Date ( b . date ) - new Date ( a . date ) ) ;
261+ . sort ( ( a , b ) => {
262+ // First sort by date (newest first)
263+ const dateCompare = new Date ( b . date ) - new Date ( a . date ) ;
264+ if ( dateCompare !== 0 ) return dateCompare ;
265+
266+ // If dates are equal, sort by version (newest first)
267+ return compareVersions ( b . version , a . version ) ;
268+ } ) ;
213269
214270 console . log ( `✅ Found ${ allVersions . length } releases` ) ;
215271
0 commit comments