diff --git a/lib/workers/package-file/dep-type.js b/lib/workers/package-file/dep-type.js index 45d22cea6ec2dc1a7872b578b5066edff9c4cec3..555e79fb038936cbfefe5f996f5e0f006cb93a6a 100644 --- a/lib/workers/package-file/dep-type.js +++ b/lib/workers/package-file/dep-type.js @@ -57,62 +57,83 @@ function getDepConfig(depTypeConfig, dep) { `Checking against ${depConfig.packageRules.length} packageRules` ); depConfig.packageRules.forEach(packageRule => { - const { + let { depTypeList, - excludePackageNames, - excludePackagePatterns, packageNames, packagePatterns, + excludePackageNames, + excludePackagePatterns, matchCurrentVersion, } = packageRule; - let applyRule; + // Setting empty arrays simplifies our logic later + depTypeList = depTypeList || []; + packageNames = packageNames || []; + packagePatterns = packagePatterns || []; + excludePackageNames = excludePackageNames || []; + excludePackagePatterns = excludePackagePatterns || []; + matchCurrentVersion = matchCurrentVersion || null; + let positiveMatch = false; + let negativeMatch = false; + // Massage a positive patterns patch if an exclude one is present if ( - (excludePackageNames || excludePackagePatterns) && - !(packageNames || packagePatterns) + (excludePackageNames.length || excludePackagePatterns.length) && + !(packageNames.length || packagePatterns.length) ) { - logger.debug( - { packageRule, dependency }, - 'packageRule is missing packageNames and packagePatterns so will match anything' - ); - applyRule = true; - } else if (packageNames && packageNames.includes(dependency)) { - logger.debug({ dependency, packageNames }, 'Matched packageNames'); - applyRule = true; - } else if (packagePatterns) { - logger.trace({ dependency }, 'Checking against packagePatterns'); - for (const packagePattern of packagePatterns) { - const packageRegex = new RegExp( - packagePattern === '^*$' || packagePattern === '*' - ? '.*' - : packagePattern - ); - logger.trace( - { dependency, packagePattern }, - 'Checking against packagePattern' - ); - if (dependency.match(packageRegex)) { - logger.trace(`${dependency} matches against ${packageRegex}`); - applyRule = true; + packagePatterns = ['.*']; + } + if (depTypeList.length) { + const isMatch = depTypeList.includes(dep.depType); + positiveMatch = positiveMatch || isMatch; + negativeMatch = negativeMatch || !isMatch; + } + if (packageNames.length || packagePatterns.length) { + let isMatch = packageNames.includes(dep.depName); + // name match is "or" so we check patterns if we didn't match names + if (!isMatch) { + for (const packagePattern of packagePatterns) { + const packageRegex = new RegExp( + packagePattern === '^*$' || packagePattern === '*' + ? '.*' + : packagePattern + ); + if (dependency.match(packageRegex)) { + logger.trace(`${dependency} matches against ${packageRegex}`); + isMatch = true; + } } } + positiveMatch = positiveMatch || isMatch; + negativeMatch = negativeMatch || !isMatch; } - if (excludePackageNames && excludePackageNames.includes(dependency)) { - applyRule = false; - } else if (excludePackagePatterns) { - for (const packagePattern of excludePackagePatterns) { - const packageRegex = new RegExp(packagePattern); + if (excludePackageNames.length) { + const isMatch = excludePackageNames.includes(dep.depName); + negativeMatch = negativeMatch || isMatch; + positiveMatch = positiveMatch || !isMatch; + } + if (excludePackagePatterns.length) { + let isMatch = false; + for (const pattern of excludePackagePatterns) { + const packageRegex = new RegExp( + pattern === '^*$' || pattern === '*' ? '.*' : pattern + ); if (dependency.match(packageRegex)) { - applyRule = false; + logger.trace(`${dependency} matches against ${packageRegex}`); + isMatch = true; } } + negativeMatch = negativeMatch || isMatch; + positiveMatch = positiveMatch || !isMatch; } - if (applyRule !== false && matchCurrentVersion) { - applyRule = intersectsSemver(dep.currentVersion, matchCurrentVersion); - } - if (applyRule !== false && depTypeList && depTypeList.length) { - applyRule = depTypeList.includes(dep.depType); + if (matchCurrentVersion) { + const isMatch = intersectsSemver( + dep.currentVersion, + matchCurrentVersion + ); + positiveMatch = positiveMatch || isMatch; + negativeMatch = negativeMatch || !isMatch; } - if (applyRule) { + // This rule is considered matched if there was at least one positive match and no negative matches + if (positiveMatch && !negativeMatch) { // Package rule config overrides any existing config depConfig = configParser.mergeChildConfig(depConfig, packageRule); delete depConfig.packageNames;