Repository: fgnass/node-dev
Pull request #249 (2021-03-20 20:04:47)

clear on start and fix clear sequence
1) add clearing screen on the first start
2) fixes clear screen sequence because with the current one terminal can be scrolled up after it is cleared (at least on windows), this is no good.

bjornstar: Thanks for submitting this, I sent you a PR with some updates for it. If you'd like to see this merged, please accept my PR.
wclr: Done.

Patch:
diff --git a/.eslintrc b/.eslintrc
index c1ee4df..2064edd 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -10,6 +10,8 @@
   },
   "rules": {
     "eqeqeq": "error",
-    "prefer-arrow-callback": "error"
+    "no-trailing-spaces": "error",
+    "prefer-arrow-callback": "error",
+    "semi": "error"
   }
 }
diff --git a/lib/clear.js b/lib/clear.js
new file mode 100644
index 0000000..9b80825
--- /dev/null
+++ b/lib/clear.js
@@ -0,0 +1,4 @@
+const control = '\u001bc';
+const clearFactory = clear => (clear ? () => process.stdout.write(control) : () => {});
+
+module.exports = { clearFactory, control };
diff --git a/lib/index.js b/lib/index.js
index b3a6c70..3d8fb26 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -3,12 +3,13 @@ const filewatcher = require('filewatcher');
 const { extname } = require('path');
 const semver = require('semver');
 
+const { clearFactory } = require('./clear');
+const { configureDeps, configureIgnore } = require('./ignore');
 const ipc = require('./ipc');
 const localPath = require('./local-path');
 const logFactory = require('./log');
 const notifyFactory = require('./notify');
 const resolveMain = require('./resolve-main');
-const { configureDeps, configureIgnore } = require('./ignore');
 
 module.exports = function (
   script,
@@ -43,12 +44,11 @@ module.exports = function (
     throw new TypeError('`nodeArgs` must be an array');
   }
 
+  const clearOutput = clearFactory(clear);
+
   const log = logFactory({ timestamp });
   const notify = notifyFactory(notifyEnabled, log);
 
-  // The child_process
-  let child;
-
   const isIgnored = configureIgnore(ignore);
   const isTooDeep = configureDeps(deps);
 
@@ -60,8 +60,11 @@ module.exports = function (
   const watcher = filewatcher({ forcePolling });
   let isPaused = false;
 
+  // The child_process
+  let child;
+
   watcher.on('change', file => {
-    if (clear) process.stdout.write('\033[2J\033[H');
+    clearOutput();
     notify('Restarting', `${file} has been modified`);
     watcher.removeAll();
     isPaused = true;
@@ -152,5 +155,6 @@ module.exports = function (
     process.exit(0);
   });
 
+  clearOutput();
   start();
 };


Test patch:
diff --git a/test/cli.js b/test/cli.js
index ce35cc5..0d792dd 100644
--- a/test/cli.js
+++ b/test/cli.js
@@ -85,3 +85,21 @@ tap.test('--expose_gc gc.js foo', t => {
   t.deepEqual(nodeArgs, ['--expose_gc']);
   t.done();
 });
+
+tap.test('clear is not enabled by default', t => {
+  const {
+    opts: { clear }
+  } = cli(['node', 'bin/node-dev', 'test']);
+
+  t.false(clear);
+  t.done();
+});
+
+tap.test('--clear enables clear', t => {
+  const {
+    opts: { clear }
+  } = cli(['node', 'bin/node-dev', '--clear', 'test']);
+
+  t.true(clear);
+  t.done();
+});
diff --git a/test/index.js b/test/index.js
index 9fad3e9..d34e931 100644
--- a/test/index.js
+++ b/test/index.js
@@ -1,4 +1,4 @@
-require('./cli.js');
-require('./log.js');
-require('./run.js');
-require('./spawn.js');
+require('./cli');
+require('./log');
+require('./run');
+require('./spawn');
diff --git a/test/spawn/clear.js b/test/spawn/clear.js
new file mode 100644
index 0000000..79b4847
--- /dev/null
+++ b/test/spawn/clear.js
@@ -0,0 +1,25 @@
+const tap = require('tap');
+
+const spawn = require('../utils/spawn');
+const touchFile = require('../utils/touch-file');
+
+const { control } = require('../../lib/clear');
+
+const reClear = new RegExp(control);
+
+tap.test('--clear', t => {
+  spawn('--clear server.js', out => {
+    if (reClear.test(out)) {
+      return out2 => {
+        if (out2.match(/touch message.js/)) {
+          touchFile('message.js');
+          return out3 => {
+            if (out3.match(/Restarting/)) {
+              return { exit: t.end.bind(t) };
+            }
+          };
+        }
+      };
+    }
+  });
+});
diff --git a/test/spawn.js b/test/spawn/index.js
similarity index 98%
rename from test/spawn.js
rename to test/spawn/index.js
index 89cd602..787ac2a 100644
--- a/test/spawn.js
+++ b/test/spawn/index.js
@@ -1,8 +1,8 @@
 const semver = require('semver');
 const tap = require('tap');
 
-const spawn = require('./utils/spawn');
-const touchFile = require('./utils/touch-file');
+const spawn = require('../utils/spawn');
+const touchFile = require('../utils/touch-file');
 
 tap.test('should pass unknown args to node binary', t => {
   spawn('--expose_gc gc.js foo', out => {
@@ -293,3 +293,5 @@ tap.test('Supports --inspect', t => {
     }
   });
 });
+
+require('./clear.js');
diff --git a/test/utils/spawn.js b/test/utils/spawn.js
index 3e3faa1..c3f5765 100644
--- a/test/utils/spawn.js
+++ b/test/utils/spawn.js
@@ -1,9 +1,13 @@
 const child = require('child_process');
 const path = require('path');
 
+const { control } = require('../../lib/clear');
+
 const bin = path.join(__dirname, '..', '..', 'bin', 'node-dev');
 const dir = path.join(__dirname, '..', 'fixture');
 
+const reClear = new RegExp(control);
+
 module.exports = (cmd, cb) => {
   const ps = child.spawn('node', [bin].concat(cmd.split(' ')), { cwd: dir });
   let err = '';
@@ -18,7 +22,9 @@ module.exports = (cmd, cb) => {
   }
 
   function outHandler(data) {
-    console.log(data.toString());
+    // Don't log clear
+    console.log(data.toString().replace(reClear, ''));
+
     const ret = cb.call(ps, data.toString());
 
     if (typeof ret === 'function') {