signal.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import {constants} from 'node:os';
  2. import {signalsByName} from 'human-signals';
  3. // Normalize signals for comparison purpose.
  4. // Also validate the signal exists.
  5. export const normalizeKillSignal = killSignal => {
  6. const optionName = 'option `killSignal`';
  7. if (killSignal === 0) {
  8. throw new TypeError(`Invalid ${optionName}: 0 cannot be used.`);
  9. }
  10. return normalizeSignal(killSignal, optionName);
  11. };
  12. export const normalizeSignalArgument = signal => signal === 0
  13. ? signal
  14. : normalizeSignal(signal, '`subprocess.kill()`\'s argument');
  15. const normalizeSignal = (signalNameOrInteger, optionName) => {
  16. if (Number.isInteger(signalNameOrInteger)) {
  17. return normalizeSignalInteger(signalNameOrInteger, optionName);
  18. }
  19. if (typeof signalNameOrInteger === 'string') {
  20. return normalizeSignalName(signalNameOrInteger, optionName);
  21. }
  22. throw new TypeError(`Invalid ${optionName} ${String(signalNameOrInteger)}: it must be a string or an integer.\n${getAvailableSignals()}`);
  23. };
  24. const normalizeSignalInteger = (signalInteger, optionName) => {
  25. if (signalsIntegerToName.has(signalInteger)) {
  26. return signalsIntegerToName.get(signalInteger);
  27. }
  28. throw new TypeError(`Invalid ${optionName} ${signalInteger}: this signal integer does not exist.\n${getAvailableSignals()}`);
  29. };
  30. const getSignalsIntegerToName = () => new Map(Object.entries(constants.signals)
  31. .reverse()
  32. .map(([signalName, signalInteger]) => [signalInteger, signalName]));
  33. const signalsIntegerToName = getSignalsIntegerToName();
  34. const normalizeSignalName = (signalName, optionName) => {
  35. if (signalName in constants.signals) {
  36. return signalName;
  37. }
  38. if (signalName.toUpperCase() in constants.signals) {
  39. throw new TypeError(`Invalid ${optionName} '${signalName}': please rename it to '${signalName.toUpperCase()}'.`);
  40. }
  41. throw new TypeError(`Invalid ${optionName} '${signalName}': this signal name does not exist.\n${getAvailableSignals()}`);
  42. };
  43. const getAvailableSignals = () => `Available signal names: ${getAvailableSignalNames()}.
  44. Available signal numbers: ${getAvailableSignalIntegers()}.`;
  45. const getAvailableSignalNames = () => Object.keys(constants.signals)
  46. .sort()
  47. .map(signalName => `'${signalName}'`)
  48. .join(', ');
  49. const getAvailableSignalIntegers = () => [...new Set(Object.values(constants.signals)
  50. .sort((signalInteger, signalIntegerTwo) => signalInteger - signalIntegerTwo))]
  51. .join(', ');
  52. // Human-friendly description of a signal
  53. export const getSignalDescription = signal => signalsByName[signal].description;