chore: disable delete confirmation in VS Code explorer
Disable the confirmation dialog when deleting files in the VS Code explorer to streamline the development workflow and reduce friction during file management operations.
This commit is contained in:
4
website/node_modules/nodemon/lib/monitor/index.js
generated
vendored
Normal file
4
website/node_modules/nodemon/lib/monitor/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
run: require('./run'),
|
||||
watch: require('./watch').watch,
|
||||
};
|
||||
288
website/node_modules/nodemon/lib/monitor/match.js
generated
vendored
Normal file
288
website/node_modules/nodemon/lib/monitor/match.js
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
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;
|
||||
minimatchOpts.windowsPathsNoEscape = 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;
|
||||
} else {
|
||||
// utils.log.detail('no match: ' + rules[i], file);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
ignored++;
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
});
|
||||
debug('good (filtered by ext)', good);
|
||||
} else {
|
||||
// else assume *.*
|
||||
debug('good', good);
|
||||
}
|
||||
|
||||
if (whitelist.length) debug('whitelist', whitelist);
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
562
website/node_modules/nodemon/lib/monitor/run.js
generated
vendored
Normal file
562
website/node_modules/nodemon/lib/monitor/run.js
generated
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
var debug = require('debug')('nodemon:run');
|
||||
const statSync = require('fs').statSync;
|
||||
var utils = require('../utils');
|
||||
var bus = utils.bus;
|
||||
var childProcess = require('child_process');
|
||||
var spawn = childProcess.spawn;
|
||||
var exec = childProcess.exec;
|
||||
var execSync = childProcess.execSync;
|
||||
var fork = childProcess.fork;
|
||||
var watch = require('./watch').watch;
|
||||
var config = require('../config');
|
||||
var child = null; // the actual child process we spawn
|
||||
var killedAfterChange = false;
|
||||
var noop = () => {};
|
||||
var restart = null;
|
||||
var psTree = require('pstree.remy');
|
||||
var path = require('path');
|
||||
var signals = require('./signals');
|
||||
const undefsafe = require('undefsafe');
|
||||
const osRelease = parseInt(require('os').release().split('.')[0], 10);
|
||||
|
||||
function run(options) {
|
||||
var cmd = config.command.raw;
|
||||
// moved up
|
||||
// we need restart function below in the global scope for run.kill
|
||||
/*jshint validthis:true*/
|
||||
restart = run.bind(this, options);
|
||||
run.restart = restart;
|
||||
|
||||
// binding options with instance of run
|
||||
// so that we can use it in run.kill
|
||||
run.options = options;
|
||||
|
||||
var runCmd = !options.runOnChangeOnly || config.lastStarted !== 0;
|
||||
if (runCmd) {
|
||||
utils.log.status('starting `' + config.command.string + '`');
|
||||
} else {
|
||||
// should just watch file if command is not to be run
|
||||
// had another alternate approach
|
||||
// to stop process being forked/spawned in the below code
|
||||
// but this approach does early exit and makes code cleaner
|
||||
debug('start watch on: %s', config.options.watch);
|
||||
if (config.options.watch !== false) {
|
||||
watch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
config.lastStarted = Date.now();
|
||||
|
||||
var stdio = ['pipe', 'pipe', 'pipe'];
|
||||
|
||||
if (config.options.stdout) {
|
||||
stdio = ['pipe', process.stdout, process.stderr];
|
||||
}
|
||||
|
||||
if (config.options.stdin === false) {
|
||||
stdio = [process.stdin, process.stdout, process.stderr];
|
||||
}
|
||||
|
||||
var sh = 'sh';
|
||||
var shFlag = '-c';
|
||||
|
||||
const binPath = process.cwd() + '/node_modules/.bin';
|
||||
|
||||
const spawnOptions = {
|
||||
env: Object.assign({}, options.execOptions.env, process.env, {
|
||||
PATH:
|
||||
binPath +
|
||||
path.delimiter +
|
||||
(undefsafe(options, '.execOptions.env.PATH') || process.env.PATH),
|
||||
}),
|
||||
stdio: stdio,
|
||||
};
|
||||
|
||||
var executable = cmd.executable;
|
||||
|
||||
if (utils.isWindows) {
|
||||
// if the exec includes a forward slash, reverse it for windows compat
|
||||
// but *only* apply to the first command, and none of the arguments.
|
||||
// ref #1251 and #1236
|
||||
if (executable.indexOf('/') !== -1) {
|
||||
executable = executable
|
||||
.split(' ')
|
||||
.map((e, i) => {
|
||||
if (i === 0) {
|
||||
return path.normalize(e);
|
||||
}
|
||||
return e;
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
// taken from npm's cli: https://git.io/vNFD4
|
||||
sh = process.env.comspec || 'cmd';
|
||||
shFlag = '/d /s /c';
|
||||
spawnOptions.windowsVerbatimArguments = true;
|
||||
spawnOptions.windowsHide = true;
|
||||
}
|
||||
|
||||
var args = runCmd ? utils.stringify(executable, cmd.args) : ':';
|
||||
var spawnArgs = [sh, [shFlag, args], spawnOptions];
|
||||
|
||||
const firstArg = cmd.args[0] || '';
|
||||
|
||||
var inBinPath = false;
|
||||
try {
|
||||
inBinPath = statSync(`${binPath}/${executable}`).isFile();
|
||||
} catch (e) {}
|
||||
|
||||
// hasStdio allows us to correctly handle stdin piping
|
||||
// see: https://git.io/vNtX3
|
||||
const hasStdio = utils.satisfies('>= 6.4.0 || < 5');
|
||||
|
||||
// forking helps with sub-process handling and tends to clean up better
|
||||
// than spawning, but it should only be used under specific conditions
|
||||
const shouldFork =
|
||||
!config.options.spawn &&
|
||||
!inBinPath &&
|
||||
!(firstArg.indexOf('-') === 0) && // don't fork if there's a node exec arg
|
||||
firstArg !== 'inspect' && // don't fork it's `inspect` debugger
|
||||
executable === 'node' && // only fork if node
|
||||
utils.version.major > 4; // only fork if node version > 4
|
||||
|
||||
if (shouldFork) {
|
||||
// this assumes the first argument is the script and slices it out, since
|
||||
// we're forking
|
||||
var forkArgs = cmd.args.slice(1);
|
||||
var env = utils.merge(options.execOptions.env, process.env);
|
||||
stdio.push('ipc');
|
||||
const forkOptions = {
|
||||
env: env,
|
||||
stdio: stdio,
|
||||
silent: !hasStdio,
|
||||
};
|
||||
if (utils.isWindows) {
|
||||
forkOptions.windowsHide = true;
|
||||
}
|
||||
child = fork(options.execOptions.script, forkArgs, forkOptions);
|
||||
utils.log.detail('forking');
|
||||
debug('fork', sh, shFlag, args);
|
||||
} else {
|
||||
utils.log.detail('spawning');
|
||||
child = spawn.apply(null, spawnArgs);
|
||||
debug('spawn', sh, shFlag, args);
|
||||
}
|
||||
|
||||
if (config.required) {
|
||||
var emit = {
|
||||
stdout: function (data) {
|
||||
bus.emit('stdout', data);
|
||||
},
|
||||
stderr: function (data) {
|
||||
bus.emit('stderr', data);
|
||||
},
|
||||
};
|
||||
|
||||
// now work out what to bind to...
|
||||
if (config.options.stdout) {
|
||||
child.on('stdout', emit.stdout).on('stderr', emit.stderr);
|
||||
} else {
|
||||
child.stdout.on('data', emit.stdout);
|
||||
child.stderr.on('data', emit.stderr);
|
||||
|
||||
bus.stdout = child.stdout;
|
||||
bus.stderr = child.stderr;
|
||||
}
|
||||
|
||||
if (shouldFork) {
|
||||
child.on('message', function (message, sendHandle) {
|
||||
bus.emit('message', message, sendHandle);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bus.emit('start');
|
||||
|
||||
utils.log.detail('child pid: ' + child.pid);
|
||||
|
||||
child.on('error', function (error) {
|
||||
bus.emit('error', error);
|
||||
if (error.code === 'ENOENT') {
|
||||
utils.log.error('unable to run executable: "' + cmd.executable + '"');
|
||||
process.exit(1);
|
||||
} else {
|
||||
utils.log.error('failed to start child process: ' + error.code);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
child.on('exit', function (code, signal) {
|
||||
if (child && child.stdin) {
|
||||
process.stdin.unpipe(child.stdin);
|
||||
}
|
||||
|
||||
if (code === 127) {
|
||||
utils.log.error(
|
||||
'failed to start process, "' + cmd.executable + '" exec not found'
|
||||
);
|
||||
bus.emit('error', code);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
// If the command failed with code 2, it may or may not be a syntax error
|
||||
// See: http://git.io/fNOAR
|
||||
// We will only assume a parse error, if the child failed quickly
|
||||
if (code === 2 && Date.now() < config.lastStarted + 500) {
|
||||
utils.log.error('process failed, unhandled exit code (2)');
|
||||
utils.log.error('');
|
||||
utils.log.error('Either the command has a syntax error,');
|
||||
utils.log.error('or it is exiting with reserved code 2.');
|
||||
utils.log.error('');
|
||||
utils.log.error('To keep nodemon running even after a code 2,');
|
||||
utils.log.error('add this to the end of your command: || exit 1');
|
||||
utils.log.error('');
|
||||
utils.log.error('Read more here: https://git.io/fNOAG');
|
||||
utils.log.error('');
|
||||
utils.log.error('nodemon will stop now so that you can fix the command.');
|
||||
utils.log.error('');
|
||||
bus.emit('error', code);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
// In case we killed the app ourselves, set the signal thusly
|
||||
if (killedAfterChange) {
|
||||
killedAfterChange = false;
|
||||
signal = config.signal;
|
||||
}
|
||||
// this is nasty, but it gives it windows support
|
||||
if (utils.isWindows && signal === 'SIGTERM') {
|
||||
signal = config.signal;
|
||||
}
|
||||
|
||||
if (signal === config.signal || code === 0) {
|
||||
// this was a clean exit, so emit exit, rather than crash
|
||||
debug('bus.emit(exit) via ' + config.signal);
|
||||
bus.emit('exit', signal);
|
||||
|
||||
// exit the monitor, but do it gracefully
|
||||
if (signal === config.signal) {
|
||||
return restart();
|
||||
}
|
||||
|
||||
if (code === 0) {
|
||||
// clean exit - wait until file change to restart
|
||||
if (runCmd) {
|
||||
utils.log.status('clean exit - waiting for changes before restart');
|
||||
}
|
||||
child = null;
|
||||
}
|
||||
} else {
|
||||
bus.emit('crash');
|
||||
|
||||
// support the old syntax of `exitcrash` - 2024-12-13
|
||||
if (options.exitcrash) {
|
||||
options.exitCrash = true;
|
||||
delete options.exitcrash;
|
||||
}
|
||||
|
||||
if (options.exitCrash) {
|
||||
utils.log.fail('app crashed');
|
||||
if (!config.required) {
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
utils.log.fail(
|
||||
'app crashed - waiting for file changes before' + ' starting...'
|
||||
);
|
||||
child = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.options.restartable) {
|
||||
// stdin needs to kick in again to be able to listen to the
|
||||
// restart command
|
||||
process.stdin.resume();
|
||||
}
|
||||
});
|
||||
|
||||
// moved the run.kill outside to handle both the cases
|
||||
// intial start
|
||||
// no start
|
||||
|
||||
// connect stdin to the child process (options.stdin is on by default)
|
||||
if (options.stdin) {
|
||||
process.stdin.resume();
|
||||
// FIXME decide whether or not we need to decide the encoding
|
||||
// process.stdin.setEncoding('utf8');
|
||||
|
||||
// swallow the stdin error if it happens
|
||||
// ref: https://github.com/remy/nodemon/issues/1195
|
||||
if (hasStdio) {
|
||||
child.stdin.on('error', () => {});
|
||||
process.stdin.pipe(child.stdin);
|
||||
} else {
|
||||
if (child.stdout) {
|
||||
child.stdout.pipe(process.stdout);
|
||||
} else {
|
||||
utils.log.error(
|
||||
'running an unsupported version of node ' + process.version
|
||||
);
|
||||
utils.log.error(
|
||||
'nodemon may not work as expected - ' +
|
||||
'please consider upgrading to LTS'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bus.once('exit', function () {
|
||||
if (child && process.stdin.unpipe) {
|
||||
// node > 0.8
|
||||
process.stdin.unpipe(child.stdin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
debug('start watch on: %s', config.options.watch);
|
||||
if (config.options.watch !== false) {
|
||||
watch();
|
||||
}
|
||||
}
|
||||
|
||||
function waitForSubProcesses(pid, callback) {
|
||||
debug('checking ps tree for pids of ' + pid);
|
||||
psTree(pid, (err, pids) => {
|
||||
if (!pids.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
utils.log.status(
|
||||
`still waiting for ${pids.length} sub-process${
|
||||
pids.length > 2 ? 'es' : ''
|
||||
} to finish...`
|
||||
);
|
||||
setTimeout(() => waitForSubProcesses(pid, callback), 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function kill(child, signal, callback) {
|
||||
if (!callback) {
|
||||
callback = noop;
|
||||
}
|
||||
|
||||
if (utils.isWindows) {
|
||||
const taskKill = () => {
|
||||
try {
|
||||
exec('taskkill /pid ' + child.pid + ' /T /F');
|
||||
} catch (e) {
|
||||
utils.log.error('Could not shutdown sub process cleanly');
|
||||
}
|
||||
};
|
||||
|
||||
// We are handling a 'SIGKILL' , 'SIGUSR2' and 'SIGUSR1' POSIX signal under Windows the
|
||||
// same way it is handled on a UNIX system: We are performing
|
||||
// a hard shutdown without waiting for the process to clean-up.
|
||||
if (
|
||||
signal === 'SIGKILL' ||
|
||||
osRelease < 10 ||
|
||||
signal === 'SIGUSR2' ||
|
||||
signal === 'SIGUSR1'
|
||||
) {
|
||||
debug('terminating process group by force: %s', child.pid);
|
||||
|
||||
// We are using the taskkill utility to terminate the whole
|
||||
// process group ('/t') of the child ('/pid') by force ('/f').
|
||||
// We need to end all sub processes, because the 'child'
|
||||
// process in this context is actually a cmd.exe wrapper.
|
||||
taskKill();
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// We are using the Windows Management Instrumentation Command-line
|
||||
// (wmic.exe) to resolve the sub-child process identifier, because the
|
||||
// 'child' process in this context is actually a cmd.exe wrapper.
|
||||
// We want to send the termination signal directly to the node process.
|
||||
// The '2> nul' silences the no process found error message.
|
||||
const resultBuffer = execSync(
|
||||
`wmic process where (ParentProcessId=${child.pid}) get ProcessId 2> nul`
|
||||
);
|
||||
const result = resultBuffer.toString().match(/^[0-9]+/m);
|
||||
|
||||
// If there is no sub-child process we fall back to the child process.
|
||||
const processId = Array.isArray(result) ? result[0] : child.pid;
|
||||
|
||||
debug('sending kill signal SIGINT to process: %s', processId);
|
||||
|
||||
// We are using the standalone 'windows-kill' executable to send the
|
||||
// standard POSIX signal 'SIGINT' to the node process. This fixes #1720.
|
||||
const windowsKill = path.normalize(
|
||||
`${__dirname}/../../bin/windows-kill.exe`
|
||||
);
|
||||
|
||||
// We have to detach the 'windows-kill' execution completely from this
|
||||
// process group to avoid terminating the nodemon process itself.
|
||||
// See: https://github.com/alirdn/windows-kill#how-it-works--limitations
|
||||
//
|
||||
// Therefore we are using 'start' to create a new cmd.exe context.
|
||||
// The '/min' option hides the new terminal window and the '/wait'
|
||||
// option lets the process wait for the command to finish.
|
||||
|
||||
execSync(
|
||||
`start "windows-kill" /min /wait "${windowsKill}" -SIGINT ${processId}`
|
||||
);
|
||||
} catch (e) {
|
||||
taskKill();
|
||||
}
|
||||
callback();
|
||||
} else {
|
||||
// we use psTree to kill the full subtree of nodemon, because when
|
||||
// spawning processes like `coffee` under the `--debug` flag, it'll spawn
|
||||
// it's own child, and that can't be killed by nodemon, so psTree gives us
|
||||
// an array of PIDs that have spawned under nodemon, and we send each the
|
||||
// configured signal (default: SIGUSR2) signal, which fixes #335
|
||||
// note that psTree also works if `ps` is missing by looking in /proc
|
||||
let sig = signal.replace('SIG', '');
|
||||
|
||||
psTree(child.pid, function (err, pids) {
|
||||
// if ps isn't native to the OS, then we need to send the numeric value
|
||||
// for the signal during the kill, `signals` is a lookup table for that.
|
||||
if (!psTree.hasPS) {
|
||||
sig = signals[signal];
|
||||
}
|
||||
|
||||
// the sub processes need to be killed from smallest to largest
|
||||
debug('sending kill signal to ' + pids.join(', '));
|
||||
|
||||
child.kill(signal);
|
||||
|
||||
pids.sort().forEach((pid) => exec(`kill -${sig} ${pid}`, noop));
|
||||
|
||||
waitForSubProcesses(child.pid, () => {
|
||||
// finally kill the main user process
|
||||
exec(`kill -${sig} ${child.pid}`, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
run.kill = function (noRestart, callback) {
|
||||
// I hate code like this :( - Remy (author of said code)
|
||||
if (typeof noRestart === 'function') {
|
||||
callback = noRestart;
|
||||
noRestart = false;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
callback = noop;
|
||||
}
|
||||
|
||||
if (child !== null) {
|
||||
// if the stdin piping is on, we need to unpipe, but also close stdin on
|
||||
// the child, otherwise linux can throw EPIPE or ECONNRESET errors.
|
||||
if (run.options.stdin) {
|
||||
process.stdin.unpipe(child.stdin);
|
||||
}
|
||||
|
||||
// For the on('exit', ...) handler above the following looks like a
|
||||
// crash, so we set the killedAfterChange flag if a restart is planned
|
||||
if (!noRestart) {
|
||||
killedAfterChange = true;
|
||||
}
|
||||
|
||||
/* Now kill the entire subtree of processes belonging to nodemon */
|
||||
var oldPid = child.pid;
|
||||
if (child) {
|
||||
kill(child, config.signal, function () {
|
||||
// this seems to fix the 0.11.x issue with the "rs" restart command,
|
||||
// though I'm unsure why. it seems like more data is streamed in to
|
||||
// stdin after we close.
|
||||
if (child && run.options.stdin && child.stdin && oldPid === child.pid) {
|
||||
child.stdin.end();
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
} else if (!noRestart) {
|
||||
// if there's no child, then we need to manually start the process
|
||||
// this is because as there was no child, the child.on('exit') event
|
||||
// handler doesn't exist which would normally trigger the restart.
|
||||
bus.once('start', callback);
|
||||
run.restart();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
run.restart = noop;
|
||||
|
||||
bus.on('quit', function onQuit(code) {
|
||||
if (code === undefined) {
|
||||
code = 0;
|
||||
}
|
||||
|
||||
// remove event listener
|
||||
var exitTimer = null;
|
||||
var exit = function () {
|
||||
clearTimeout(exitTimer);
|
||||
exit = noop; // null out in case of race condition
|
||||
child = null;
|
||||
if (!config.required) {
|
||||
// Execute all other quit listeners.
|
||||
bus.listeners('quit').forEach(function (listener) {
|
||||
if (listener !== onQuit) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
process.exit(code);
|
||||
} else {
|
||||
bus.emit('exit');
|
||||
}
|
||||
};
|
||||
|
||||
// if we're not running already, don't bother with trying to kill
|
||||
if (config.run === false) {
|
||||
return exit();
|
||||
}
|
||||
|
||||
// immediately try to stop any polling
|
||||
config.run = false;
|
||||
|
||||
if (child) {
|
||||
// give up waiting for the kids after 10 seconds
|
||||
exitTimer = setTimeout(exit, 10 * 1000);
|
||||
child.removeAllListeners('exit');
|
||||
child.once('exit', exit);
|
||||
|
||||
kill(child, 'SIGINT');
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
});
|
||||
|
||||
bus.on('restart', function () {
|
||||
// run.kill will send a SIGINT to the child process, which will cause it
|
||||
// to terminate, which in turn uses the 'exit' event handler to restart
|
||||
run.kill();
|
||||
});
|
||||
|
||||
// remove the child file on exit
|
||||
process.on('exit', function () {
|
||||
utils.log.detail('exiting');
|
||||
if (child) {
|
||||
child.kill();
|
||||
}
|
||||
});
|
||||
|
||||
// because windows borks when listening for the SIG* events
|
||||
if (!utils.isWindows) {
|
||||
bus.once('boot', () => {
|
||||
// usual suspect: ctrl+c exit
|
||||
process.once('SIGINT', () => bus.emit('quit', 130));
|
||||
process.once('SIGTERM', () => {
|
||||
bus.emit('quit', 143);
|
||||
if (child) {
|
||||
child.kill('SIGTERM');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
34
website/node_modules/nodemon/lib/monitor/signals.js
generated
vendored
Normal file
34
website/node_modules/nodemon/lib/monitor/signals.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
module.exports = {
|
||||
SIGHUP: 1,
|
||||
SIGINT: 2,
|
||||
SIGQUIT: 3,
|
||||
SIGILL: 4,
|
||||
SIGTRAP: 5,
|
||||
SIGABRT: 6,
|
||||
SIGBUS: 7,
|
||||
SIGFPE: 8,
|
||||
SIGKILL: 9,
|
||||
SIGUSR1: 10,
|
||||
SIGSEGV: 11,
|
||||
SIGUSR2: 12,
|
||||
SIGPIPE: 13,
|
||||
SIGALRM: 14,
|
||||
SIGTERM: 15,
|
||||
SIGSTKFLT: 16,
|
||||
SIGCHLD: 17,
|
||||
SIGCONT: 18,
|
||||
SIGSTOP: 19,
|
||||
SIGTSTP: 20,
|
||||
SIGTTIN: 21,
|
||||
SIGTTOU: 22,
|
||||
SIGURG: 23,
|
||||
SIGXCPU: 24,
|
||||
SIGXFSZ: 25,
|
||||
SIGVTALRM: 26,
|
||||
SIGPROF: 27,
|
||||
SIGWINCH: 28,
|
||||
SIGIO: 29,
|
||||
SIGPWR: 30,
|
||||
SIGSYS: 31,
|
||||
SIGRTMIN: 35,
|
||||
}
|
||||
244
website/node_modules/nodemon/lib/monitor/watch.js
generated
vendored
Normal file
244
website/node_modules/nodemon/lib/monitor/watch.js
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
module.exports.watch = watch;
|
||||
module.exports.resetWatchers = resetWatchers;
|
||||
|
||||
var debug = require('debug')('nodemon:watch');
|
||||
var debugRoot = require('debug')('nodemon');
|
||||
var chokidar = require('chokidar');
|
||||
var undefsafe = require('undefsafe');
|
||||
var config = require('../config');
|
||||
var path = require('path');
|
||||
var utils = require('../utils');
|
||||
var bus = utils.bus;
|
||||
var match = require('./match');
|
||||
var watchers = [];
|
||||
var debouncedBus;
|
||||
|
||||
bus.on('reset', resetWatchers);
|
||||
|
||||
function resetWatchers() {
|
||||
debugRoot('resetting watchers');
|
||||
watchers.forEach(function (watcher) {
|
||||
watcher.close();
|
||||
});
|
||||
watchers = [];
|
||||
}
|
||||
|
||||
function watch() {
|
||||
if (watchers.length) {
|
||||
debug('early exit on watch, still watching (%s)', watchers.length);
|
||||
return;
|
||||
}
|
||||
|
||||
var dirs = [].slice.call(config.dirs);
|
||||
|
||||
debugRoot('start watch on: %s', dirs.join(', '));
|
||||
const rootIgnored = config.options.ignore;
|
||||
debugRoot('ignored', rootIgnored);
|
||||
|
||||
var watchedFiles = [];
|
||||
|
||||
const promise = new Promise(function (resolve) {
|
||||
const dotFilePattern = /[/\\]\./;
|
||||
var ignored = match.rulesToMonitor(
|
||||
[], // not needed
|
||||
Array.from(rootIgnored),
|
||||
config
|
||||
).map(pattern => pattern.slice(1));
|
||||
|
||||
const addDotFile = dirs.filter(dir => dir.match(dotFilePattern));
|
||||
|
||||
// don't ignore dotfiles if explicitly watched.
|
||||
if (addDotFile.length === 0) {
|
||||
ignored.push(dotFilePattern);
|
||||
}
|
||||
|
||||
var watchOptions = {
|
||||
ignorePermissionErrors: true,
|
||||
ignored: ignored,
|
||||
persistent: true,
|
||||
usePolling: config.options.legacyWatch || false,
|
||||
interval: config.options.pollingInterval,
|
||||
// note to future developer: I've gone back and forth on adding `cwd`
|
||||
// to the props and in some cases it fixes bugs but typically it causes
|
||||
// bugs elsewhere (since nodemon is used is so many ways). the final
|
||||
// decision is to *not* use it at all and work around it
|
||||
// cwd: ...
|
||||
};
|
||||
|
||||
if (utils.isWindows) {
|
||||
watchOptions.disableGlobbing = true;
|
||||
}
|
||||
|
||||
if (utils.isIBMi) {
|
||||
watchOptions.usePolling = true;
|
||||
}
|
||||
|
||||
if (process.env.TEST) {
|
||||
watchOptions.useFsEvents = false;
|
||||
}
|
||||
|
||||
var watcher = chokidar.watch(
|
||||
dirs,
|
||||
Object.assign({}, watchOptions, config.options.watchOptions || {})
|
||||
);
|
||||
|
||||
watcher.ready = false;
|
||||
|
||||
var total = 0;
|
||||
|
||||
watcher.on('change', filterAndRestart);
|
||||
watcher.on('unlink', filterAndRestart);
|
||||
watcher.on('add', function (file) {
|
||||
if (watcher.ready) {
|
||||
return filterAndRestart(file);
|
||||
}
|
||||
|
||||
watchedFiles.push(file);
|
||||
bus.emit('watching', file);
|
||||
debug('chokidar watching: %s', file);
|
||||
});
|
||||
watcher.on('ready', function () {
|
||||
watchedFiles = Array.from(new Set(watchedFiles)); // ensure no dupes
|
||||
total = watchedFiles.length;
|
||||
watcher.ready = true;
|
||||
resolve(total);
|
||||
debugRoot('watch is complete');
|
||||
});
|
||||
|
||||
watcher.on('error', function (error) {
|
||||
if (error.code === 'EINVAL') {
|
||||
utils.log.error(
|
||||
'Internal watch failed. Likely cause: too many ' +
|
||||
'files being watched (perhaps from the root of a drive?\n' +
|
||||
'See https://github.com/paulmillr/chokidar/issues/229 for details'
|
||||
);
|
||||
} else {
|
||||
utils.log.error('Internal watch failed: ' + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
watchers.push(watcher);
|
||||
});
|
||||
|
||||
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 () {
|
||||
utils.log.detail(`watching ${watchedFiles.length} file${
|
||||
watchedFiles.length === 1 ? '' : 's'}`);
|
||||
return watchedFiles;
|
||||
});
|
||||
}
|
||||
|
||||
function filterAndRestart(files) {
|
||||
if (!Array.isArray(files)) {
|
||||
files = [files];
|
||||
}
|
||||
|
||||
if (files.length) {
|
||||
var cwd = process.cwd();
|
||||
if (this.options && this.options.cwd) {
|
||||
cwd = this.options.cwd;
|
||||
}
|
||||
|
||||
utils.log.detail(
|
||||
'files triggering change check: ' +
|
||||
files
|
||||
.map(file => {
|
||||
const res = path.relative(cwd, file);
|
||||
return res;
|
||||
})
|
||||
.join(', ')
|
||||
);
|
||||
|
||||
// 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(f => {
|
||||
if (f.indexOf(':') === -1) { return f; }
|
||||
return f[0].toUpperCase() + f.slice(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
debug('filterAndRestart on', files);
|
||||
|
||||
var matched = match(
|
||||
files,
|
||||
config.options.monitor,
|
||||
undefsafe(config, 'options.execOptions.ext')
|
||||
);
|
||||
|
||||
debug('matched?', JSON.stringify(matched));
|
||||
|
||||
// if there's no matches, then test to see if the changed file is the
|
||||
// running script, if so, let's allow a restart
|
||||
if (config.options.execOptions && config.options.execOptions.script) {
|
||||
const script = path.resolve(config.options.execOptions.script);
|
||||
if (matched.result.length === 0 && script) {
|
||||
const length = script.length;
|
||||
files.find(file => {
|
||||
if (file.substr(-length, length) === script) {
|
||||
matched = {
|
||||
result: [file],
|
||||
total: 1,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
utils.log.detail(
|
||||
'changes after filters (before/after): ' +
|
||||
[files.length, matched.result.length].join('/')
|
||||
);
|
||||
|
||||
// reset the last check so we're only looking at recently modified files
|
||||
config.lastStarted = Date.now();
|
||||
|
||||
if (matched.result.length) {
|
||||
if (config.options.delay > 0) {
|
||||
utils.log.detail('delaying restart for ' + config.options.delay + 'ms');
|
||||
if (debouncedBus === undefined) {
|
||||
debouncedBus = debounce(restartBus, config.options.delay);
|
||||
}
|
||||
debouncedBus(matched);
|
||||
} else {
|
||||
return restartBus(matched);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function restartBus(matched) {
|
||||
utils.log.status('restarting due to changes...');
|
||||
matched.result.map(file => {
|
||||
utils.log.detail(path.relative(process.cwd(), file));
|
||||
});
|
||||
|
||||
if (config.options.verbose) {
|
||||
utils.log._log('');
|
||||
}
|
||||
|
||||
bus.emit('restart', matched.result);
|
||||
}
|
||||
|
||||
function debounce(fn, delay) {
|
||||
var timer = null;
|
||||
return function () {
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() =>fn.apply(context, args), delay);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user