const minimatch = require('minimatch');

const { intersectsSemver } = require('./semver');
const { mergeChildConfig } = require('../config');

module.exports = {
  applyPackageRules,
};

function applyPackageRules(config) {
  const { packageFile, depType, depName, currentVersion } = config;
  let depConfig = { ...config };
  logger.trace(
    { depName, packageRules: depConfig.packageRules },
    `Checking against ${depConfig.packageRules.length} packageRules`
  );
  depConfig.packageRules.forEach(packageRule => {
    let {
      paths,
      depTypeList,
      packageNames,
      packagePatterns,
      excludePackageNames,
      excludePackagePatterns,
      matchCurrentVersion,
    } = packageRule;
    // Setting empty arrays simplifies our logic later
    paths = paths || [];
    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.length || excludePackagePatterns.length) &&
      !(packageNames.length || packagePatterns.length)
    ) {
      packagePatterns = ['.*'];
    }
    if (paths.length) {
      const isMatch = paths.some(
        rulePath =>
          packageFile.includes(rulePath) || minimatch(packageFile, rulePath)
      );
      positiveMatch = positiveMatch || isMatch;
      negativeMatch = negativeMatch || !isMatch;
    }
    if (depTypeList.length) {
      const isMatch = depTypeList.includes(depType);
      positiveMatch = positiveMatch || isMatch;
      negativeMatch = negativeMatch || !isMatch;
    }
    if (packageNames.length || packagePatterns.length) {
      let isMatch = packageNames.includes(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 (depName.match(packageRegex)) {
            logger.trace(`${depName} matches against ${packageRegex}`);
            isMatch = true;
          }
        }
      }
      positiveMatch = positiveMatch || isMatch;
      negativeMatch = negativeMatch || !isMatch;
    }
    if (excludePackageNames.length) {
      const isMatch = excludePackageNames.includes(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 (depName.match(packageRegex)) {
          logger.trace(`${depName} matches against ${packageRegex}`);
          isMatch = true;
        }
      }
      negativeMatch = negativeMatch || isMatch;
      positiveMatch = positiveMatch || !isMatch;
    }
    if (matchCurrentVersion) {
      const isMatch = intersectsSemver(currentVersion, matchCurrentVersion);
      positiveMatch = positiveMatch || isMatch;
      negativeMatch = negativeMatch || !isMatch;
    }
    // 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 = mergeChildConfig(depConfig, packageRule);
      delete depConfig.packageNames;
      delete depConfig.packagePatterns;
      delete depConfig.excludePackageNames;
      delete depConfig.excludePackagePatterns;
      delete depConfig.depTypeList;
      delete depConfig.matchCurrentVersion;
    }
    delete depConfig.packageFules;
  });
  return depConfig;
}

@@ -207,17 +207,22 @@
 geRules(
-c
+inputC
 onfig) %7B
@@ -222,16 +222,51 @@
 nfig) %7B%0A
+  let config = %7B ...inputConfig %7D;%0A
   const 
@@ -329,41 +329,8 @@
 ig;%0A
-  let depConfig = %7B ...config %7D;%0A
   lo
@@ -370,20 +370,17 @@
 eRules: 
-depC
+c
 onfig.pa
@@ -417,20 +417,17 @@
 ainst $%7B
-depC
+c
 onfig.pa
@@ -466,20 +466,17 @@
 %0A  );%0A  
-depC
+c
 onfig.pa
@@ -3668,20 +3668,17 @@
 g%0A      
-depC
+c
 onfig = 
@@ -3694,20 +3694,17 @@
 dConfig(
-depC
+c
 onfig, p
@@ -3721,36 +3721,33 @@
 );%0A      delete 
-depC
+c
 onfig.packageNam
@@ -3755,36 +3755,33 @@
 s;%0A      delete 
-depC
+c
 onfig.packagePat
@@ -3792,36 +3792,33 @@
 s;%0A      delete 
-depC
+c
 onfig.excludePac
@@ -3837,28 +3837,25 @@
      delete 
-depC
+c
 onfig.exclud
@@ -3881,28 +3881,25 @@
      delete 
-depC
+c
 onfig.depTyp
@@ -3914,28 +3914,25 @@
      delete 
-depC
+c
 onfig.matchC
@@ -3963,20 +3963,17 @@
  delete 
-depC
+c
 onfig.pa
@@ -4003,12 +4003,9 @@
 urn 
-depC
+c
 onfi

rename package rules config for readability