You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							277 lines
						
					
					
						
							6.6 KiB
						
					
					
				
			
		
		
	
	
							277 lines
						
					
					
						
							6.6 KiB
						
					
					
				| const minimatch = require('minimatch');
 | |
| const path = require('path');
 | |
| const fs = require('fs');
 | |
| const debug = require('debug')('nodemon:match');
 | |
| const utils = require('../utils');
 | |
| 
 | |
| module.exports = match;
 | |
| module.exports.rulesToMonitor = rulesToMonitor;
 | |
| 
 | |
| function rulesToMonitor(watch, ignore, config) {
 | |
|   var monitor = [];
 | |
| 
 | |
|   if (!Array.isArray(ignore)) {
 | |
|     if (ignore) {
 | |
|       ignore = [ignore];
 | |
|     } else {
 | |
|       ignore = [];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!Array.isArray(watch)) {
 | |
|     if (watch) {
 | |
|       watch = [watch];
 | |
|     } else {
 | |
|       watch = [];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (watch && watch.length) {
 | |
|     monitor = utils.clone(watch);
 | |
|   }
 | |
| 
 | |
|   if (ignore) {
 | |
|     [].push.apply(monitor, (ignore || []).map(function (rule) {
 | |
|       return '!' + rule;
 | |
|     }));
 | |
|   }
 | |
| 
 | |
|   var cwd = process.cwd();
 | |
| 
 | |
|   // next check if the monitored paths are actual directories
 | |
|   // or just patterns - and expand the rule to include *.*
 | |
|   monitor = monitor.map(function (rule) {
 | |
|     var not = rule.slice(0, 1) === '!';
 | |
| 
 | |
|     if (not) {
 | |
|       rule = rule.slice(1);
 | |
|     }
 | |
| 
 | |
|     if (rule === '.' || rule === '.*') {
 | |
|       rule = '*.*';
 | |
|     }
 | |
| 
 | |
|     var dir = path.resolve(cwd, rule);
 | |
| 
 | |
|     try {
 | |
|       var stat = fs.statSync(dir);
 | |
|       if (stat.isDirectory()) {
 | |
|         rule = dir;
 | |
|         if (rule.slice(-1) !== '/') {
 | |
|           rule += '/';
 | |
|         }
 | |
|         rule += '**/*';
 | |
| 
 | |
|         // `!not` ... sorry.
 | |
|         if (!not) {
 | |
|           config.dirs.push(dir);
 | |
|         }
 | |
|       } else {
 | |
|         // ensures we end up in the check that tries to get a base directory
 | |
|         // and then adds it to the watch list
 | |
|         throw new Error();
 | |
|       }
 | |
|     } catch (e) {
 | |
|       var base = tryBaseDir(dir);
 | |
|       if (!not && base) {
 | |
|         if (config.dirs.indexOf(base) === -1) {
 | |
|           config.dirs.push(base);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (rule.slice(-1) === '/') {
 | |
|       // just slap on a * anyway
 | |
|       rule += '*';
 | |
|     }
 | |
| 
 | |
|     // if the url ends with * but not **/* and not *.*
 | |
|     // then convert to **/* - somehow it was missed :-\
 | |
|     if (rule.slice(-4) !== '**/*' &&
 | |
|       rule.slice(-1) === '*' &&
 | |
|       rule.indexOf('*.') === -1) {
 | |
| 
 | |
|       if (rule.slice(-2) !== '**') {
 | |
|         rule += '*/*';
 | |
|       }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     return (not ? '!' : '') + rule;
 | |
|   });
 | |
| 
 | |
|   return monitor;
 | |
| }
 | |
| 
 | |
| function tryBaseDir(dir) {
 | |
|   var stat;
 | |
|   if (/[?*\{\[]+/.test(dir)) { // if this is pattern, then try to find the base
 | |
|     try {
 | |
|       var base = path.dirname(dir.replace(/([?*\{\[]+.*$)/, 'foo'));
 | |
|       stat = fs.statSync(base);
 | |
|       if (stat.isDirectory()) {
 | |
|         return base;
 | |
|       }
 | |
|     } catch (error) {
 | |
|       // console.log(error);
 | |
|     }
 | |
|   } else {
 | |
|     try {
 | |
|       stat = fs.statSync(dir);
 | |
|       // if this path is actually a single file that exists, then just monitor
 | |
|       // that, *specifically*.
 | |
|       if (stat.isFile() || stat.isDirectory()) {
 | |
|         return dir;
 | |
|       }
 | |
|     } catch (e) { }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function match(files, monitor, ext) {
 | |
|   // sort the rules by highest specificity (based on number of slashes)
 | |
|   // ignore rules (!) get sorted highest as they take precedent
 | |
|   const cwd = process.cwd();
 | |
|   var rules = monitor.sort(function (a, b) {
 | |
|     var r = b.split(path.sep).length - a.split(path.sep).length;
 | |
|     var aIsIgnore = a.slice(0, 1) === '!';
 | |
|     var bIsIgnore = b.slice(0, 1) === '!';
 | |
| 
 | |
|     if (aIsIgnore || bIsIgnore) {
 | |
|       if (aIsIgnore) {
 | |
|         return -1;
 | |
|       }
 | |
| 
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|     if (r === 0) {
 | |
|       return b.length - a.length;
 | |
|     }
 | |
|     return r;
 | |
|   }).map(function (s) {
 | |
|     var prefix = s.slice(0, 1);
 | |
| 
 | |
|     if (prefix === '!') {
 | |
|       if (s.indexOf('!' + cwd) === 0) {
 | |
|         return s;
 | |
|       }
 | |
| 
 | |
|       // if it starts with a period, then let's get the relative path
 | |
|       if (s.indexOf('!.') === 0) {
 | |
|         return '!' + path.resolve(cwd, s.substring(1));
 | |
|       }
 | |
| 
 | |
|       return '!**' + (prefix !== path.sep ? path.sep : '') + s.slice(1);
 | |
|     }
 | |
| 
 | |
|     // if it starts with a period, then let's get the relative path
 | |
|     if (s.indexOf('.') === 0) {
 | |
|       return path.resolve(cwd, s);
 | |
|     }
 | |
| 
 | |
|     if (s.indexOf(cwd) === 0) {
 | |
|       return s;
 | |
|     }
 | |
| 
 | |
|     return '**' + (prefix !== path.sep ? path.sep : '') + s;
 | |
|   });
 | |
| 
 | |
|   debug('rules', rules);
 | |
| 
 | |
|   var good = [];
 | |
|   var whitelist = []; // files that we won't check against the extension
 | |
|   var ignored = 0;
 | |
|   var watched = 0;
 | |
|   var usedRules = [];
 | |
|   var minimatchOpts = {
 | |
|     dot: true,
 | |
|   };
 | |
| 
 | |
|   // enable case-insensitivity on Windows
 | |
|   if (utils.isWindows) {
 | |
|     minimatchOpts.nocase = true;
 | |
|   }
 | |
| 
 | |
|   files.forEach(function (file) {
 | |
|     file = path.resolve(cwd, file);
 | |
| 
 | |
|     var matched = false;
 | |
|     for (var i = 0; i < rules.length; i++) {
 | |
|       if (rules[i].slice(0, 1) === '!') {
 | |
|         if (!minimatch(file, rules[i], minimatchOpts)) {
 | |
|           debug('ignored', file, 'rule:', rules[i]);
 | |
|           ignored++;
 | |
|           matched = true;
 | |
|           break;
 | |
|         }
 | |
|       } else {
 | |
|         debug('matched', file, 'rule:', rules[i]);
 | |
|         if (minimatch(file, rules[i], minimatchOpts)) {
 | |
|           watched++;
 | |
| 
 | |
|           // don't repeat the output if a rule is matched
 | |
|           if (usedRules.indexOf(rules[i]) === -1) {
 | |
|             usedRules.push(rules[i]);
 | |
|             utils.log.detail('matched rule: ' + rules[i]);
 | |
|           }
 | |
| 
 | |
|           // if the rule doesn't match the WATCH EVERYTHING
 | |
|           // but *does* match a rule that ends with *.*, then
 | |
|           // white list it - in that we don't run it through
 | |
|           // the extension check too.
 | |
|           if (rules[i] !== '**' + path.sep + '*.*' &&
 | |
|             rules[i].slice(-3) === '*.*') {
 | |
|             whitelist.push(file);
 | |
|           } else if (path.basename(file) === path.basename(rules[i])) {
 | |
|             // if the file matches the actual rule, then it's put on whitelist
 | |
|             whitelist.push(file);
 | |
|           } else {
 | |
|             good.push(file);
 | |
|           }
 | |
|           matched = true;
 | |
|           break;
 | |
|         } else {
 | |
|           // utils.log.detail('no match: ' + rules[i], file);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (!matched) {
 | |
|       ignored++;
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   debug('good', good)
 | |
| 
 | |
|   // finally check the good files against the extensions that we're monitoring
 | |
|   if (ext) {
 | |
|     if (ext.indexOf(',') === -1) {
 | |
|       ext = '**/*.' + ext;
 | |
|     } else {
 | |
|       ext = '**/*.{' + ext + '}';
 | |
|     }
 | |
| 
 | |
|     good = good.filter(function (file) {
 | |
|       // only compare the filename to the extension test
 | |
|       return minimatch(path.basename(file), ext, minimatchOpts);
 | |
|     });
 | |
|   } // else assume *.*
 | |
| 
 | |
|   var result = good.concat(whitelist);
 | |
| 
 | |
|   if (utils.isWindows) {
 | |
|     // fix for windows testing - I *think* this is okay to do
 | |
|     result = result.map(function (file) {
 | |
|       return file.slice(0, 1).toLowerCase() + file.slice(1);
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   return {
 | |
|     result: result,
 | |
|     ignored: ignored,
 | |
|     watched: watched,
 | |
|     total: files.length,
 | |
|   };
 | |
| }
 |