no-process-exit.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. 'use strict';
  2. const {methodCallSelector, STATIC_REQUIRE_SELECTOR} = require('./selectors/index.js');
  3. const MESSAGE_ID = 'no-process-exit';
  4. const messages = {
  5. [MESSAGE_ID]: 'Only use `process.exit()` in CLI apps. Throw an error instead.',
  6. };
  7. const importWorkerThreadsSelector = [
  8. // `require('worker_threads')`
  9. [
  10. STATIC_REQUIRE_SELECTOR,
  11. '[arguments.0.value="worker_threads"]',
  12. ].join(''),
  13. // `import workerThreads from 'worker_threads'`
  14. [
  15. 'ImportDeclaration',
  16. '[source.type="Literal"]',
  17. '[source.value="worker_threads"]',
  18. ].join(''),
  19. ].join(', ');
  20. const processOnOrOnceCallSelector = methodCallSelector({
  21. object: 'process',
  22. methods: ['on', 'once'],
  23. minimumArguments: 1,
  24. });
  25. const processExitCallSelector = methodCallSelector({
  26. object: 'process',
  27. method: 'exit',
  28. });
  29. /** @param {import('eslint').Rule.RuleContext} context */
  30. const create = context => {
  31. const startsWithHashBang = context.getSourceCode().lines[0].indexOf('#!') === 0;
  32. if (startsWithHashBang) {
  33. return {};
  34. }
  35. let processEventHandler;
  36. // Only report if it's outside an worker thread context. See #328.
  37. let requiredWorkerThreadsModule = false;
  38. const problemNodes = [];
  39. return {
  40. // Check `worker_threads` require / import
  41. [importWorkerThreadsSelector]: () => {
  42. requiredWorkerThreadsModule = true;
  43. },
  44. // Check `process.on` / `process.once` call
  45. [processOnOrOnceCallSelector]: node => {
  46. processEventHandler = node;
  47. },
  48. // Check `process.exit` call
  49. [processExitCallSelector]: node => {
  50. if (!processEventHandler) {
  51. problemNodes.push(node);
  52. }
  53. },
  54. 'CallExpression:exit': node => {
  55. if (node === processEventHandler) {
  56. processEventHandler = undefined;
  57. }
  58. },
  59. * 'Program:exit'() {
  60. if (!requiredWorkerThreadsModule) {
  61. for (const node of problemNodes) {
  62. yield {
  63. node,
  64. messageId: MESSAGE_ID,
  65. };
  66. }
  67. }
  68. },
  69. };
  70. };
  71. /** @type {import('eslint').Rule.RuleModule} */
  72. module.exports = {
  73. create,
  74. meta: {
  75. type: 'suggestion',
  76. docs: {
  77. description: 'Disallow `process.exit()`.',
  78. },
  79. messages,
  80. },
  81. };