@@ -21,6 +21,8 @@ import {
2121} from '../versioning-strategy' ;
2222import { logger as defaultLogger , Logger } from '../util/logger' ;
2323
24+ const SHORT_YEAR_EPOCH = 2000 ;
25+
2426const CALVER_PLACEHOLDERS : Record < string , string > = {
2527 YYYY : '\\d{4}' ,
2628 '0Y' : '\\d{2,3}' ,
@@ -246,6 +248,14 @@ class CalendarVersionUpdate implements VersionUpdater {
246248 ) ;
247249 }
248250
251+ const versionDate = extractDateFromSegments ( parsed . segments , tokens ) ;
252+ if ( versionDate && versionDate > this . currentDate ) {
253+ throw new Error (
254+ `Cannot bump version "${ version } ": the version date is newer than the current date. ` +
255+ `Ensure the system date is correct or use a release-as override.`
256+ ) ;
257+ }
258+
249259 const newSegments : CalVerSegment [ ] = [ ] ;
250260 let dateChanged = false ;
251261 let shouldResetLower = false ;
@@ -380,6 +390,64 @@ function isSemanticSegment(type: string): type is 'MAJOR' | 'MINOR' | 'MICRO' {
380390 return [ 'MAJOR' , 'MINOR' , 'MICRO' ] . includes ( type ) ;
381391}
382392
393+ function extractDateFromSegments (
394+ segments : CalVerSegment [ ] ,
395+ tokens : CalVerSegment [ 'type' ] [ ]
396+ ) : Date | null {
397+ let year : number | null = null ;
398+ let month : number | null = null ;
399+ let day : number | null = null ;
400+ let week : number | null = null ;
401+
402+ for ( let i = 0 ; i < segments . length ; i ++ ) {
403+ const token = tokens [ i ] ;
404+ const value = segments [ i ] . value ;
405+
406+ switch ( token ) {
407+ case 'YYYY' :
408+ year = value ;
409+ break ;
410+ case 'YY' :
411+ case '0Y' :
412+ year = value + SHORT_YEAR_EPOCH ;
413+ break ;
414+ case 'MM' :
415+ case '0M' :
416+ month = value ;
417+ break ;
418+ case 'DD' :
419+ case '0D' :
420+ day = value ;
421+ break ;
422+ case 'WW' :
423+ case '0W' :
424+ week = value ;
425+ break ;
426+ }
427+ }
428+
429+ if ( year === null ) {
430+ return null ;
431+ }
432+
433+ if ( month !== null && day !== null ) {
434+ return new Date ( Date . UTC ( year , month - 1 , day ) ) ;
435+ }
436+
437+ if ( month !== null ) {
438+ return new Date ( Date . UTC ( year , month - 1 , 1 ) ) ;
439+ }
440+
441+ if ( week !== null ) {
442+ const jan1 = new Date ( Date . UTC ( year , 0 , 1 ) ) ;
443+ const jan1DayOfWeek = ( jan1 . getUTCDay ( ) + 6 ) % 7 ;
444+ const daysToAdd = ( week - 1 ) * 7 - jan1DayOfWeek ;
445+ return new Date ( Date . UTC ( year , 0 , 1 + daysToAdd ) ) ;
446+ }
447+
448+ return new Date ( Date . UTC ( year , 0 , 1 ) ) ;
449+ }
450+
383451// Week of year where January 1 is always in week 1.
384452// Weeks align with calendar weeks (starting Monday).
385453function getWeekOfYear ( date : Date ) : number {
@@ -397,7 +465,7 @@ function formatSegment(type: CalVerSegment['type'], date: Date): string {
397465 const month = date . getUTCMonth ( ) + 1 ;
398466 const day = date . getUTCDate ( ) ;
399467 const week = getWeekOfYear ( date ) ;
400- const shortYear = year - 2000 ;
468+ const shortYear = year - SHORT_YEAR_EPOCH ;
401469
402470 switch ( type ) {
403471 case 'YYYY' :
0 commit comments