securityos/node_modules/eslint-plugin-unicorn/rules/no-process-exit.js

90 lines
2.0 KiB
JavaScript

'use strict';
const {methodCallSelector, STATIC_REQUIRE_SELECTOR} = require('./selectors/index.js');
const MESSAGE_ID = 'no-process-exit';
const messages = {
[MESSAGE_ID]: 'Only use `process.exit()` in CLI apps. Throw an error instead.',
};
const importWorkerThreadsSelector = [
// `require('worker_threads')`
[
STATIC_REQUIRE_SELECTOR,
'[arguments.0.value="worker_threads"]',
].join(''),
// `import workerThreads from 'worker_threads'`
[
'ImportDeclaration',
'[source.type="Literal"]',
'[source.value="worker_threads"]',
].join(''),
].join(', ');
const processOnOrOnceCallSelector = methodCallSelector({
object: 'process',
methods: ['on', 'once'],
minimumArguments: 1,
});
const processExitCallSelector = methodCallSelector({
object: 'process',
method: 'exit',
});
/** @param {import('eslint').Rule.RuleContext} context */
const create = context => {
const startsWithHashBang = context.getSourceCode().lines[0].indexOf('#!') === 0;
if (startsWithHashBang) {
return {};
}
let processEventHandler;
// Only report if it's outside an worker thread context. See #328.
let requiredWorkerThreadsModule = false;
const problemNodes = [];
return {
// Check `worker_threads` require / import
[importWorkerThreadsSelector]() {
requiredWorkerThreadsModule = true;
},
// Check `process.on` / `process.once` call
[processOnOrOnceCallSelector](node) {
processEventHandler = node;
},
// Check `process.exit` call
[processExitCallSelector](node) {
if (!processEventHandler) {
problemNodes.push(node);
}
},
'CallExpression:exit'(node) {
if (node === processEventHandler) {
processEventHandler = undefined;
}
},
* 'Program:exit'() {
if (!requiredWorkerThreadsModule) {
for (const node of problemNodes) {
yield {
node,
messageId: MESSAGE_ID,
};
}
}
},
};
};
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Disallow `process.exit()`.',
},
messages,
},
};