options.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import path from 'node:path';
  2. import process from 'node:process';
  3. import crossSpawn from 'cross-spawn';
  4. import {npmRunPathEnv} from 'npm-run-path';
  5. import {normalizeForceKillAfterDelay} from '../terminate/kill.js';
  6. import {normalizeKillSignal} from '../terminate/signal.js';
  7. import {validateCancelSignal} from '../terminate/cancel.js';
  8. import {validateGracefulCancel} from '../terminate/graceful.js';
  9. import {validateTimeout} from '../terminate/timeout.js';
  10. import {handleNodeOption} from '../methods/node.js';
  11. import {validateIpcInputOption} from '../ipc/ipc-input.js';
  12. import {validateEncoding, BINARY_ENCODINGS} from './encoding-option.js';
  13. import {normalizeCwd} from './cwd.js';
  14. import {normalizeFileUrl} from './file-url.js';
  15. import {normalizeFdSpecificOptions} from './specific.js';
  16. // Normalize the options object, and sometimes also the file paths and arguments.
  17. // Applies default values, validate allowed options, normalize them.
  18. export const normalizeOptions = (filePath, rawArguments, rawOptions) => {
  19. rawOptions.cwd = normalizeCwd(rawOptions.cwd);
  20. const [processedFile, processedArguments, processedOptions] = handleNodeOption(filePath, rawArguments, rawOptions);
  21. const {command: file, args: commandArguments, options: initialOptions} = crossSpawn._parse(processedFile, processedArguments, processedOptions);
  22. const fdOptions = normalizeFdSpecificOptions(initialOptions);
  23. const options = addDefaultOptions(fdOptions);
  24. validateTimeout(options);
  25. validateEncoding(options);
  26. validateIpcInputOption(options);
  27. validateCancelSignal(options);
  28. validateGracefulCancel(options);
  29. options.shell = normalizeFileUrl(options.shell);
  30. options.env = getEnv(options);
  31. options.killSignal = normalizeKillSignal(options.killSignal);
  32. options.forceKillAfterDelay = normalizeForceKillAfterDelay(options.forceKillAfterDelay);
  33. options.lines = options.lines.map((lines, fdNumber) => lines && !BINARY_ENCODINGS.has(options.encoding) && options.buffer[fdNumber]);
  34. if (process.platform === 'win32' && path.basename(file, '.exe') === 'cmd') {
  35. // #116
  36. commandArguments.unshift('/q');
  37. }
  38. return {file, commandArguments, options};
  39. };
  40. const addDefaultOptions = ({
  41. extendEnv = true,
  42. preferLocal = false,
  43. cwd,
  44. localDir: localDirectory = cwd,
  45. encoding = 'utf8',
  46. reject = true,
  47. cleanup = true,
  48. all = false,
  49. windowsHide = true,
  50. killSignal = 'SIGTERM',
  51. forceKillAfterDelay = true,
  52. gracefulCancel = false,
  53. ipcInput,
  54. ipc = ipcInput !== undefined || gracefulCancel,
  55. serialization = 'advanced',
  56. ...options
  57. }) => ({
  58. ...options,
  59. extendEnv,
  60. preferLocal,
  61. cwd,
  62. localDirectory,
  63. encoding,
  64. reject,
  65. cleanup,
  66. all,
  67. windowsHide,
  68. killSignal,
  69. forceKillAfterDelay,
  70. gracefulCancel,
  71. ipcInput,
  72. ipc,
  73. serialization,
  74. });
  75. const getEnv = ({env: envOption, extendEnv, preferLocal, node, localDirectory, nodePath}) => {
  76. const env = extendEnv ? {...process.env, ...envOption} : envOption;
  77. if (preferLocal || node) {
  78. return npmRunPathEnv({
  79. env,
  80. cwd: localDirectory,
  81. execPath: nodePath,
  82. preferLocal,
  83. addExecPath: node,
  84. });
  85. }
  86. return env;
  87. };