import { gte , lt , lte , satisfies } from '@renovatebot/pep440' ; import { parse as parseRange } from '@renovatebot/pep440/lib/specifier.js' ; import { parse as parseVersion } from '@renovatebot/pep440/lib/version.js' ; import { logger } from '../../logger' ; import { regEx } from '../../util/regex' ; import type { NewValueConfig } from '../types' ; function getFutureVersion ( baseVersion , newVersion , step ) { const toRelease = parseVersion ( newVersion ) ?. release ?? [ ] ; const baseRelease = parseVersion ( baseVersion ) ?. release ?? [ ] ; let found = false ; const futureRelease = baseRelease . map ( ( basePart , index ) => { if ( found ) { return 0 ; } const toPart = toRelease [ index ] || 0 ; if ( toPart > basePart ) { found = true ; return toPart + step ; } return toPart ; } ) ; if ( ! found ) { futureRelease [ futureRelease . length - 1 ] += step ; } return futureRelease . join ( '.' ) ; } interface Range { operator : string ; prefix : string ; version : string ; } export function getNewValue ( { currentValue , rangeStrategy , currentVersion , newVersion , } ) { if ( rangeStrategy === 'pin' ) { return '==' + newVersion ; } if ( currentValue === currentVersion ) { return newVersion ; } const ranges = parseRange ( currentValue ) ; if ( ! ranges ) { logger . warn ( { currentValue } , 'Invalid pep440 currentValue' ) ; return null ; } if ( ! ranges . length ) { logger . warn ( 'Empty currentValue: ' + currentValue ) ; return currentValue ; } if ( rangeStrategy === 'auto' || rangeStrategy === 'replace' ) { if ( satisfies ( newVersion , currentValue ) ) { return currentValue ; } } if ( ! [ 'replace' , 'bump' ] . includes ( rangeStrategy ) ) { logger . debug ( 'Unsupported rangeStrategy: ' + rangeStrategy + '. Using "replace" instead.' ) ; return getNewValue ( { currentValue , rangeStrategy : 'replace' , currentVersion , newVersion , } ) ; } if ( ranges . some ( ( range ) => range . operator === '===' ) ) { logger . warn ( { currentValue } , 'PEP440 arbitrary equality (===) not supported' ) ; return null ; } let result = ranges . map ( ( range ) => { if ( range . operator === '!=' ) { return range . operator + range . version ; } if ( [ '>' , '>=' ] . includes ( range . operator ) ) { if ( lte ( newVersion , range . version ) ) { return '>=' + newVersion ; } if ( rangeStrategy === 'bump' && range . operator === '>=' ) { return range . operator + newVersion ; } return range . operator + range . version ; } if ( range . operator === '<' ) { if ( gte ( newVersion , range . version ) ) { const futureVersion = getFutureVersion ( range . version , newVersion , 1 ) ; return range . operator + futureVersion ; } return range . operator + range . version ; } if ( range . prefix ) { const futureVersion = getFutureVersion ( range . version , newVersion , 0 ) ; return range . operator + futureVersion + '.*' ; } if ( [ '==' , '~=' , '<=' ] . includes ( range . operator ) ) { return range . operator + newVersion ; } logger . error ( { newVersion , currentValue , range } , 'pep440: failed to process range' ) ; return null ; } ) . filter ( Boolean ) . join ( ', ' ) ; if ( result . includes ( ', ' ) && ! currentValue . includes ( ', ' ) ) { result = result . replace ( regEx ( /, /g ) , ',' ) ; } if ( ! satisfies ( newVersion , result ) ) { logger . warn ( { result , newVersion , currentValue } , 'pep440: failed to calculate newValue' ) ; return null ; } return result ; } export function isLessThanRange ( input , range ) { try { let invertResult = true ; const results = range . split ( ',' ) . map ( ( x ) => x . replace ( regEx ( /\s*/g ) , '' ) . split ( regEx ( /(~=|==|!=|<=|>=|<|>|===)/ ) ) . slice ( 1 ) ) . map ( ( [ op , version ] ) => { if ( [ '!=' , '<=' , '<' ] . includes ( op ) ) { return true ; } invertResult = false ; if ( [ '~=' , '==' , '>=' , '===' ] . includes ( op ) ) { return lt ( input , version ) ; } if ( op === '>' ) { return lte ( input , version ) ; } return false ; } ) ; const result = results . every ( ( res ) => res === true ) ; return invertResult ? ! result : result ; } catch ( err ) { return false ; } }