import { GetPkgReleasesConfig , getPkgReleases , } from '../../../../../datasource' ; import { logger } from '../../../../../logger' ; import { api as semver } from '../../../../../versioning/npm' ; /**
 * Finds the first stable version of parentName after parentStartingVersion which either:
 * - depends on targetDepName@targetVersion or a range which it satisfies, OR
 * - removes the dependency targetDepName altogether, OR
 * - depends on any version of targetDepName higher than targetVersion
 */ export async function findFirstParentVersion ( parentName , parentStartingVersion , targetDepName , targetVersion ) { if ( ! semver . isVersion ( parentStartingVersion ) ) { logger . debug ( 'parentStartingVersion is not a version - cannot remediate' ) ; return null ; } logger . debug ( `Finding first version of ${ parentName } starting with ${ parentStartingVersion } which supports >= ${ targetDepName }@${ targetVersion }` ) ; try { let lookupConfig = { datasource : 'npm' , depName : targetDepName , } ; const targetDep = await getPkgReleases ( lookupConfig ) ; if ( ! targetDep ) { logger . warn ( { targetDepName } , 'Could not look up target dependency for remediation' ) ; return null ; } const targetVersions = targetDep . releases . map ( ( release ) => release . version ) . filter ( ( version ) => semver . isVersion ( version ) && semver . isStable ( version ) && ( version === targetVersion || semver . isGreaterThan ( version , targetVersion ) ) ) ; lookupConfig = { datasource : 'npm' , depName : parentName , } ; const parentDep = await getPkgReleases ( lookupConfig ) ; if ( ! parentDep ) { logger . info ( { parentName } , 'Could not look up parent dependency for remediation' ) ; return null ; } const parentVersions = parentDep . releases . map ( ( release ) => release . version ) . filter ( ( version ) => semver . isVersion ( version ) && semver . isStable ( version ) && ( version === parentStartingVersion || semver . isGreaterThan ( version , parentStartingVersion ) ) ) . sort ( ( v1 , v2 ) => semver . sortVersions ( v1 , v2 ) ) ; for ( const parentVersion of parentVersions ) { const constraint = parentDep . releases . find ( ( release ) => release . version === parentVersion ) . dependencies ?. [ targetDepName ] ; if ( ! constraint ) { logger . debug ( `${ targetDepName } has been removed from ${ parentName }@${ parentVersion }` ) ; return parentVersion ; } if ( semver . matches ( targetVersion , constraint ) ) { logger . debug ( `${ targetDepName } needs ${ parentName }@${ parentVersion } which uses constraint "${ constraint }" in order to update to ${ targetVersion }` ) ; return parentVersion ; } if ( semver . isVersion ( constraint ) ) { if ( semver . isGreaterThan ( constraint , targetVersion ) ) { logger . debug ( `${ targetDepName } needs ${ parentName }@${ parentVersion } which uses version "${ constraint }" in order to update to greater than ${ targetVersion }` ) ; return parentVersion ; } } else if ( targetVersions . some ( ( version ) => semver . matches ( version , constraint ) ) ) { logger . debug ( `${ targetDepName } needs ${ parentName }@${ parentVersion } which uses constraint "${ constraint }" in order to update to greater than ${ targetVersion }` ) ; return parentVersion ; } } } catch ( err ) { logger . warn ( { parentName , parentStartingVersion , targetDepName , targetVersion , err } , 'findFirstParentVersion error' ) ; return null ; } logger . debug ( `Could not find a matching version` ) ; return null ; }