Repository: remy/nodemon
Pull request #1375 (2018-07-02 10:35:11)

docs: change README.md to make the intro more concise
change README.md intro to clarify and remove redundant text


Patch:
diff --git a/README.md b/README.md
index b23b64b..1625b5e 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,9 @@
 
 # nodemon
 
-For use during development of a node.js based application.
+nodemon is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected. 
 
-nodemon will watch the files in the directory in which nodemon was started, and if any files change, nodemon will automatically restart your node application.
-
-nodemon does **not** require *any* changes to your code or method of development. nodemon wraps your node application and keeps an eye on any files that have changed. Remember that nodemon is a replacement wrapper for `node`, think of it as replacing the word "node" on the command line when you run your script.
+nodemon does **not** require *any* additional changes to your code or method of development. nodemon is a replacement wrapper for `node`, to use `nodemon` replace the word `node` on the command line when executing your script.
 
 [![NPM version](https://badge.fury.io/js/nodemon.svg)](https://npmjs.org/package/nodemon)
 [![Travis Status](https://travis-ci.org/remy/nodemon.svg?branch=master)](https://travis-ci.org/remy/nodemon) [![Backers on Open Collective](https://opencollective.com/nodemon/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/nodemon/sponsors/badge.svg)](#sponsors)
diff --git a/doc/cli/help.txt b/doc/cli/help.txt
index 11b749f..adc4ba8 100644
--- a/doc/cli/help.txt
+++ b/doc/cli/help.txt
@@ -5,7 +5,7 @@
   --config file ............ alternate nodemon.json config file to use
   -e, --ext ................ extensions to look for, ie. js,jade,hbs.
   -x, --exec app ........... execute script with "app", ie. -x "python -v".
-  -w, --watch dir........... watch directory "dir" or files. use once for
+  -w, --watch path.......... watch directory "path" or files. use once for
                              each directory or file to watch.
   -i, --ignore ............. ignore specific files or directories.
   -V, --verbose ............ show detail on what is causing restarts.
diff --git a/faq.md b/faq.md
index e94d004..5149734 100644
--- a/faq.md
+++ b/faq.md
@@ -226,6 +226,28 @@ Try the following command on terminal:
 echo fs.inotify.max_user_watches=582222 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
 ```
 
+## "Port in use" with --inspect flag and docker
+
+The workaround is to use [kill-port](https://github.com/tiaanduplessis/kill-port) to close off the debugger port, used similarly to:
+
+```bash
+nodemon --delay 80ms --exec 'kill-port -k 9228/tcp; node --inspect=0.0.0.0:9228 ./app/http.js'
+```
+
+[Original suggestion here](https://github.com/remy/nodemon/issues/1050#issuecomment-323680697) and [addition information here](https://github.com/remy/nodemon/issues/1346#issuecomment-401218386).
+
+## Windows: nodemon keeps restarting without changes
+
+This _might_ be related to a Microsoft Windows release pertaining to the OS and breaking `fsevents` module (which is used by [chokidar](https://github.com/paulmillr/chokidar) - the underlying watch package).
+
+The workaround is to run the following command:
+
+```bash
+fsutil behavior set disablelastaccess 1
+```
+
+[Futher reading thread](https://github.com/remy/nodemon/issues/1354)
+
 ## Error: Cannot find module 'internal/util/types'
 
 If you see the error `Cannot find module 'internal/util/types'`, the error is solved with a clean npm cache and trying to reinstall the dependency you're working with.
diff --git a/lib/monitor/match.js b/lib/monitor/match.js
index 1c7c4cf..3261ced 100644
--- a/lib/monitor/match.js
+++ b/lib/monitor/match.js
@@ -160,7 +160,8 @@ function match(files, monitor, ext) {
       return '!**' + (prefix !== path.sep ? path.sep : '') + s.slice(1);
     }
 
-    if (s.slice(0, 2) === '..') {
+    // if it starts with a period, then let's get the relative path
+    if (s.indexOf('.') === 0) {
       return path.resolve(cwd, s);
     }
 
diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js
index a961825..5b6e38c 100644
--- a/lib/monitor/watch.js
+++ b/lib/monitor/watch.js
@@ -7,7 +7,6 @@ var chokidar = require('chokidar');
 var undefsafe = require('undefsafe');
 var config = require('../config');
 var path = require('path');
-const fs = require('fs');
 var utils = require('../utils');
 var bus = utils.bus;
 var match = require('./match');
@@ -36,7 +35,6 @@ function watch() {
   const rootIgnored = config.options.ignore;
   debugRoot('ignored', rootIgnored);
 
-  var promises = [];
   var watchedFiles = [];
 
   const promise = new Promise(function (resolve) {
@@ -54,16 +52,6 @@ function watch() {
       ignored.push(dotFilePattern);
     }
 
-    dirs = dirs.map(dir => {
-      // if the directory is a file, it somehow causes
-      // windows to lose the filename upon change
-      if (fs.statSync(dir).isFile()) {
-        dir = path.dirname(dir);
-      }
-
-      return dir;
-    });
-
     var watchOptions = {
       ignorePermissionErrors: true,
       ignored: ignored,
@@ -124,10 +112,12 @@ function watch() {
   });
 
   return promise.catch(e => {
+    // this is a core error and it should break nodemon - so I have to break
+    // out of a promise using the setTimeout
     setTimeout(() => {
       throw e;
     });
-  }).then(function (res) {
+  }).then(function () {
     utils.log.detail(`watching ${watchedFiles.length} file${
       watchedFiles.length === 1 ? '' : 's'}`);
     return watchedFiles;
@@ -138,6 +128,7 @@ function filterAndRestart(files) {
   if (!Array.isArray(files)) {
     files = [files];
   }
+
   if (files.length) {
     var cwd = process.cwd();
     if (this.options && this.options.cwd) {
@@ -147,20 +138,23 @@ function filterAndRestart(files) {
     utils.log.detail(
       'files triggering change check: ' +
       files
-        .map(function (file) {
+        .map(file => {
           const res = path.relative(cwd, file);
           return res;
         })
         .join(', ')
     );
 
-    files = files.map(file => {
+    // make sure the path is right and drop an empty
+    // filenames (sometimes on windows)
+    files = files.filter(Boolean).map(file => {
       return path.relative(process.cwd(), path.relative(cwd, file));
     });
 
     if (utils.isWindows) {
       // ensure the drive letter is in uppercase (c:\foo -> C:\foo)
-      files = files.map(function (f) {
+      files = files.map(f => {
+        if (f.indexOf(':') === -1) { return f; }
         return f[0].toUpperCase() + f.slice(1);
       });
     }
@@ -218,7 +212,7 @@ function filterAndRestart(files) {
 
 function restartBus(matched) {
   utils.log.status('restarting due to changes...');
-  matched.result.map(function (file) {
+  matched.result.map(file => {
     utils.log.detail(path.relative(process.cwd(), file));
   });
 
@@ -232,11 +226,9 @@ function restartBus(matched) {
 function debounce(fn, delay) {
   var timer = null;
   return function () {
-    var context = this;
-    var args = arguments;
+    const context = this;
+    const args = arguments;
     clearTimeout(timer);
-    timer = setTimeout(function () {
-      fn.apply(context, args);
-    }, delay);
+    timer = setTimeout(() =>fn.apply(context, args), delay);
   };
 }
diff --git a/lib/nodemon.js b/lib/nodemon.js
index 13961b8..836e387 100644
--- a/lib/nodemon.js
+++ b/lib/nodemon.js
@@ -96,44 +96,53 @@ function nodemon(settings) {
     });
 
     // echo out notices about running state
-    if (config.options.stdin && config.options.restartable) {
-      // allow nodemon to restart when the use types 'rs\n'
-      process.stdin.resume();
-      process.stdin.setEncoding('utf8');
-      process.stdin.on('data', function (data) {
-        data = (data + '').trim().toLowerCase();
-
-        // if the keys entered match the restartable value, then restart!
-        if (data === config.options.restartable) {
-          bus.emit('restart');
-        }
-      });
-    } else if (config.options.stdin) {
-      // if 'restartable' is disabled (via a nodemon.json)
-      // then it's possible we're being used with a REPL
+    if (config.options.stdin) {
       // so let's make sure we don't eat the key presses
       // but also, since we're wrapping, watch out for
-      // special keys, like ctrl+c x 2 or '.exit' or ctrl+d
+      // special keys, like ctrl+c x 2 or '.exit' or ctrl+d or ctrl+l
       var ctrlC = false;
       var buffer = '';
+      const rs = config.options.restartable;
 
+      process.stdin.setEncoding('utf8');
       process.stdin.on('data', function (data) {
-        buffer += data;
         data = data.toString();
-        var chr = data.charCodeAt(0);
+        buffer += data;
+        const chr = data.charCodeAt(0);
+
+        // if restartable, echo back
+        if (rs) {
+          if (chr === 13) {
+            process.stdout.write('\n');
+          }
+          // this prevents cursor keys from working.
+          process.stdout.write(String.fromCharCode(chr));
+        }
+
         if (chr === 3) {
-          if (ctrlC) {
-            process.exit();
+          // if restartable, assume ctrl+c will break immediately
+          if (ctrlC || rs) {
+            process.exit(rs ? 1 : 0);
           }
           ctrlC = true;
-        } else if (buffer === '.exit' || chr === 4) {
+          return;
+        } else if (buffer === '.exit' || chr === 4) { // ctrl+d
           process.exit();
-        } else if (ctrlC || chr === 10) {
-          ctrlC = false;
+        } else if (chr === 13 || chr === 10) { // enter / carriage return
+          const input = buffer.toString().trim().toLowerCase();
+          if (input === rs) {
+            bus.emit('restart');
+          }
+          buffer = '';
+        } else if (chr === 12) { // ctrl+l
+          console.clear();
           buffer = '';
         }
+        ctrlC = false;
       });
-      process.stdin.setRawMode(true);
+      if (process.stdin.setRawMode) {
+        process.stdin.setRawMode(true);
+      }
     }
 
     if (config.options.restartable) {


Test patch:
diff --git a/test/monitor/count.test.js b/test/monitor/count.test.js
index 30ff80f..b2d317d 100644
--- a/test/monitor/count.test.js
+++ b/test/monitor/count.test.js
@@ -38,6 +38,27 @@ describe('watch count', function () {
     });
   });
 
+  it('should not watch directory when given a single file', function (done) {
+    process.chdir('test/fixtures/watch-count/');
+    var watching = 0;
+    nodemon({ script: appjs, verbose: true, watch: appjs }).on('start', function () {
+      setTimeout(function () {
+        assert(watching === 1, `got ${watching} files`);
+        nodemon.once('exit', done).emit('quit');
+      }, 200);
+    }).on('watching', file => {
+      watching++;
+    }).on('log', function (data) {
+      var match = null;
+      var count = 0;
+      if (match = data.message.match(watchRe)) {
+        count = match[1].replace(',', '') * 1;
+        assert(count === 1, `log showing ${count} files`);
+      }
+    });
+  });
+
+
   it('should ignore node_modules from any dir', function (done) {
     process.chdir('test/fixtures/watch-count/lib');
     nodemon({ script: appjs, verbose: true, watch: '..' }).on('start', function () {
diff --git a/test/monitor/match.test.js b/test/monitor/match.test.js
index 19674f3..6f59db6 100644
--- a/test/monitor/match.test.js
+++ b/test/monitor/match.test.js
@@ -557,4 +557,18 @@ describe('watcher', function() {
       }
     );
   });
+
+  it('should watch relative paths', function() {
+    const monitor = match.rulesToMonitor([ './http.js' ], [], {
+      dirs: [],
+    });
+
+    var matched = match(
+      ['http.js'],
+      monitor,
+      'js,mjs,json'
+    );
+    assert(matched.result.length === 1, 'found match ' + matched.results);
+  });
+
 });