@karmaniverous/get-dotenv 4.4.3 → 4.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -14,6 +14,7 @@ var require$$0$2 = require('path');
14
14
  var require$$0$1 = require('fs');
15
15
  var promises = require('node:timers/promises');
16
16
  var node_os = require('node:os');
17
+ var node_v8 = require('node:v8');
17
18
  var node_stream = require('node:stream');
18
19
  var node_buffer = require('node:buffer');
19
20
  var promises$1 = require('node:stream/promises');
@@ -4463,64 +4464,6 @@ const fallbackSymbols = {...common$7, ...specialFallbackSymbols};
4463
4464
  const shouldUseMain = isUnicodeSupported();
4464
4465
  const figures = shouldUseMain ? mainSymbols : fallbackSymbols;
4465
4466
 
4466
- // Write synchronously to ensure lines are properly ordered and not interleaved with `stdout`
4467
- const verboseLog = (string, verboseId, icon, color) => {
4468
- const prefixedLines = addPrefix(string, verboseId, icon, color);
4469
- fs$v.writeFileSync(STDERR_FD, `${prefixedLines}\n`);
4470
- };
4471
-
4472
- const STDERR_FD = 2;
4473
-
4474
- const addPrefix = (string, verboseId, icon, color) => string.includes('\n')
4475
- ? string
4476
- .split('\n')
4477
- .map(line => addPrefixToLine(line, verboseId, icon, color))
4478
- .join('\n')
4479
- : addPrefixToLine(string, verboseId, icon, color);
4480
-
4481
- const addPrefixToLine = (line, verboseId, icon, color = identity$1) => [
4482
- gray(`[${getTimestamp()}]`),
4483
- gray(`[${verboseId}]`),
4484
- color(ICONS[icon]),
4485
- color(line),
4486
- ].join(' ');
4487
-
4488
- const identity$1 = string => string;
4489
-
4490
- // Prepending the timestamp allows debugging the slow paths of a subprocess
4491
- const getTimestamp = () => {
4492
- const date = new Date();
4493
- return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`;
4494
- };
4495
-
4496
- const padField = (field, padding) => String(field).padStart(padding, '0');
4497
-
4498
- const ICONS = {
4499
- command: '$',
4500
- pipedCommand: '|',
4501
- output: ' ',
4502
- error: figures.cross,
4503
- warning: figures.warning,
4504
- success: figures.tick,
4505
- };
4506
-
4507
- // When `verbose` is `short|full`, print each command
4508
- const logCommand = (escapedCommand, {verbose, verboseId}, {piped = false}) => {
4509
- if (!isVerbose(verbose)) {
4510
- return;
4511
- }
4512
-
4513
- const icon = piped ? 'pipedCommand' : 'command';
4514
- verboseLog(escapedCommand, verboseId, icon, bold);
4515
- };
4516
-
4517
- // Start counting time before spawning the subprocess
4518
- const getStartTime = () => process$3.hrtime.bigint();
4519
-
4520
- // Compute duration after the subprocess ended.
4521
- // Printed by the `verbose` option.
4522
- const getDurationMs = startTime => Number(process$3.hrtime.bigint() - startTime) / 1e6;
4523
-
4524
4467
  // Compute `result.command` and `result.escapedCommand`
4525
4468
  const joinCommand = (filePath, rawArguments) => {
4526
4469
  const fileAndArguments = [filePath, ...rawArguments];
@@ -4591,6 +4534,75 @@ const quoteString = escapedArgument => {
4591
4534
 
4592
4535
  const NO_ESCAPE_REGEXP = /^[\w./-]+$/;
4593
4536
 
4537
+ // Write synchronously to ensure lines are properly ordered and not interleaved with `stdout`
4538
+ const verboseLog = (string, verboseId, icon, color) => {
4539
+ const prefixedLines = addPrefix(string, verboseId, icon, color);
4540
+ fs$v.writeFileSync(STDERR_FD, `${prefixedLines}\n`);
4541
+ };
4542
+
4543
+ const STDERR_FD = 2;
4544
+
4545
+ const addPrefix = (string, verboseId, icon, color) => string.includes('\n')
4546
+ ? string
4547
+ .split('\n')
4548
+ .map(line => addPrefixToLine(line, verboseId, icon, color))
4549
+ .join('\n')
4550
+ : addPrefixToLine(string, verboseId, icon, color);
4551
+
4552
+ const addPrefixToLine = (line, verboseId, icon, color = identity$1) => [
4553
+ gray(`[${getTimestamp()}]`),
4554
+ gray(`[${verboseId}]`),
4555
+ color(ICONS[icon]),
4556
+ color(line),
4557
+ ].join(' ');
4558
+
4559
+ const identity$1 = string => string;
4560
+
4561
+ // Prepending the timestamp allows debugging the slow paths of a subprocess
4562
+ const getTimestamp = () => {
4563
+ const date = new Date();
4564
+ return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`;
4565
+ };
4566
+
4567
+ const padField = (field, padding) => String(field).padStart(padding, '0');
4568
+
4569
+ const ICONS = {
4570
+ command: '$',
4571
+ pipedCommand: '|',
4572
+ output: ' ',
4573
+ ipc: '*',
4574
+ error: figures.cross,
4575
+ warning: figures.warning,
4576
+ success: figures.tick,
4577
+ };
4578
+
4579
+ // Serialize any type to a line string, for logging
4580
+ const serializeLogMessage = message => {
4581
+ const messageString = typeof message === 'string' ? message : node_util.inspect(message);
4582
+ const escapedMessage = escapeLines(messageString);
4583
+ return escapedMessage.replaceAll('\t', ' '.repeat(TAB_SIZE));
4584
+ };
4585
+
4586
+ // Same as `util.inspect()`
4587
+ const TAB_SIZE = 2;
4588
+
4589
+ // When `verbose` is `short|full`, print each command
4590
+ const logCommand = (escapedCommand, {verbose, verboseId}, {piped = false}) => {
4591
+ if (!isVerbose(verbose)) {
4592
+ return;
4593
+ }
4594
+
4595
+ const icon = piped ? 'pipedCommand' : 'command';
4596
+ verboseLog(escapedCommand, verboseId, icon, bold);
4597
+ };
4598
+
4599
+ // Start counting time before spawning the subprocess
4600
+ const getStartTime = () => process$3.hrtime.bigint();
4601
+
4602
+ // Compute duration after the subprocess ended.
4603
+ // Printed by the `verbose` option.
4604
+ const getDurationMs = startTime => Number(process$3.hrtime.bigint() - startTime) / 1e6;
4605
+
4594
4606
  const isStandardStream = stream => STANDARD_STREAMS.includes(stream);
4595
4607
  const STANDARD_STREAMS = [process$3.stdin, process$3.stdout, process$3.stderr];
4596
4608
  const STANDARD_STREAMS_ALIASES = ['stdin', 'stdout', 'stderr'];
@@ -4610,7 +4622,7 @@ const normalizeFdSpecificOptions = options => {
4610
4622
  };
4611
4623
 
4612
4624
  const normalizeFdSpecificOption = (options, optionName) => {
4613
- const optionBaseArray = Array.from({length: getStdioLength(options)});
4625
+ const optionBaseArray = Array.from({length: getStdioLength(options) + 1});
4614
4626
  const optionArray = normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName);
4615
4627
  return addDefaultValue$1(optionArray, optionName);
4616
4628
  };
@@ -4645,10 +4657,14 @@ const getFdNameOrder = fdName => {
4645
4657
  };
4646
4658
 
4647
4659
  const parseFdName = (fdName, optionName, optionArray) => {
4660
+ if (fdName === 'ipc') {
4661
+ return [optionArray.length - 1];
4662
+ }
4663
+
4648
4664
  const fdNumber = parseFd(fdName);
4649
4665
  if (fdNumber === undefined || fdNumber === 0) {
4650
4666
  throw new TypeError(`"${optionName}.${fdName}" is invalid.
4651
- It must be "${optionName}.stdout", "${optionName}.stderr", "${optionName}.all", or "${optionName}.fd3", "${optionName}.fd4" (and so on).`);
4667
+ It must be "${optionName}.stdout", "${optionName}.stderr", "${optionName}.all", "${optionName}.ipc", or "${optionName}.fd3", "${optionName}.fd4" (and so on).`);
4652
4668
  }
4653
4669
 
4654
4670
  if (fdNumber >= optionArray.length) {
@@ -5442,6 +5458,386 @@ setErrorName(ExecaError, ExecaError.name);
5442
5458
  class ExecaSyncError extends Error {}
5443
5459
  setErrorName(ExecaSyncError, ExecaSyncError.name);
5444
5460
 
5461
+ const getRealtimeSignals=()=>{
5462
+ const length=SIGRTMAX-SIGRTMIN+1;
5463
+ return Array.from({length},getRealtimeSignal)
5464
+ };
5465
+
5466
+ const getRealtimeSignal=(value,index)=>({
5467
+ name:`SIGRT${index+1}`,
5468
+ number:SIGRTMIN+index,
5469
+ action:"terminate",
5470
+ description:"Application-specific signal (realtime)",
5471
+ standard:"posix"
5472
+ });
5473
+
5474
+ const SIGRTMIN=34;
5475
+ const SIGRTMAX=64;
5476
+
5477
+ const SIGNALS=[
5478
+ {
5479
+ name:"SIGHUP",
5480
+ number:1,
5481
+ action:"terminate",
5482
+ description:"Terminal closed",
5483
+ standard:"posix"
5484
+ },
5485
+ {
5486
+ name:"SIGINT",
5487
+ number:2,
5488
+ action:"terminate",
5489
+ description:"User interruption with CTRL-C",
5490
+ standard:"ansi"
5491
+ },
5492
+ {
5493
+ name:"SIGQUIT",
5494
+ number:3,
5495
+ action:"core",
5496
+ description:"User interruption with CTRL-\\",
5497
+ standard:"posix"
5498
+ },
5499
+ {
5500
+ name:"SIGILL",
5501
+ number:4,
5502
+ action:"core",
5503
+ description:"Invalid machine instruction",
5504
+ standard:"ansi"
5505
+ },
5506
+ {
5507
+ name:"SIGTRAP",
5508
+ number:5,
5509
+ action:"core",
5510
+ description:"Debugger breakpoint",
5511
+ standard:"posix"
5512
+ },
5513
+ {
5514
+ name:"SIGABRT",
5515
+ number:6,
5516
+ action:"core",
5517
+ description:"Aborted",
5518
+ standard:"ansi"
5519
+ },
5520
+ {
5521
+ name:"SIGIOT",
5522
+ number:6,
5523
+ action:"core",
5524
+ description:"Aborted",
5525
+ standard:"bsd"
5526
+ },
5527
+ {
5528
+ name:"SIGBUS",
5529
+ number:7,
5530
+ action:"core",
5531
+ description:
5532
+ "Bus error due to misaligned, non-existing address or paging error",
5533
+ standard:"bsd"
5534
+ },
5535
+ {
5536
+ name:"SIGEMT",
5537
+ number:7,
5538
+ action:"terminate",
5539
+ description:"Command should be emulated but is not implemented",
5540
+ standard:"other"
5541
+ },
5542
+ {
5543
+ name:"SIGFPE",
5544
+ number:8,
5545
+ action:"core",
5546
+ description:"Floating point arithmetic error",
5547
+ standard:"ansi"
5548
+ },
5549
+ {
5550
+ name:"SIGKILL",
5551
+ number:9,
5552
+ action:"terminate",
5553
+ description:"Forced termination",
5554
+ standard:"posix",
5555
+ forced:true
5556
+ },
5557
+ {
5558
+ name:"SIGUSR1",
5559
+ number:10,
5560
+ action:"terminate",
5561
+ description:"Application-specific signal",
5562
+ standard:"posix"
5563
+ },
5564
+ {
5565
+ name:"SIGSEGV",
5566
+ number:11,
5567
+ action:"core",
5568
+ description:"Segmentation fault",
5569
+ standard:"ansi"
5570
+ },
5571
+ {
5572
+ name:"SIGUSR2",
5573
+ number:12,
5574
+ action:"terminate",
5575
+ description:"Application-specific signal",
5576
+ standard:"posix"
5577
+ },
5578
+ {
5579
+ name:"SIGPIPE",
5580
+ number:13,
5581
+ action:"terminate",
5582
+ description:"Broken pipe or socket",
5583
+ standard:"posix"
5584
+ },
5585
+ {
5586
+ name:"SIGALRM",
5587
+ number:14,
5588
+ action:"terminate",
5589
+ description:"Timeout or timer",
5590
+ standard:"posix"
5591
+ },
5592
+ {
5593
+ name:"SIGTERM",
5594
+ number:15,
5595
+ action:"terminate",
5596
+ description:"Termination",
5597
+ standard:"ansi"
5598
+ },
5599
+ {
5600
+ name:"SIGSTKFLT",
5601
+ number:16,
5602
+ action:"terminate",
5603
+ description:"Stack is empty or overflowed",
5604
+ standard:"other"
5605
+ },
5606
+ {
5607
+ name:"SIGCHLD",
5608
+ number:17,
5609
+ action:"ignore",
5610
+ description:"Child process terminated, paused or unpaused",
5611
+ standard:"posix"
5612
+ },
5613
+ {
5614
+ name:"SIGCLD",
5615
+ number:17,
5616
+ action:"ignore",
5617
+ description:"Child process terminated, paused or unpaused",
5618
+ standard:"other"
5619
+ },
5620
+ {
5621
+ name:"SIGCONT",
5622
+ number:18,
5623
+ action:"unpause",
5624
+ description:"Unpaused",
5625
+ standard:"posix",
5626
+ forced:true
5627
+ },
5628
+ {
5629
+ name:"SIGSTOP",
5630
+ number:19,
5631
+ action:"pause",
5632
+ description:"Paused",
5633
+ standard:"posix",
5634
+ forced:true
5635
+ },
5636
+ {
5637
+ name:"SIGTSTP",
5638
+ number:20,
5639
+ action:"pause",
5640
+ description:"Paused using CTRL-Z or \"suspend\"",
5641
+ standard:"posix"
5642
+ },
5643
+ {
5644
+ name:"SIGTTIN",
5645
+ number:21,
5646
+ action:"pause",
5647
+ description:"Background process cannot read terminal input",
5648
+ standard:"posix"
5649
+ },
5650
+ {
5651
+ name:"SIGBREAK",
5652
+ number:21,
5653
+ action:"terminate",
5654
+ description:"User interruption with CTRL-BREAK",
5655
+ standard:"other"
5656
+ },
5657
+ {
5658
+ name:"SIGTTOU",
5659
+ number:22,
5660
+ action:"pause",
5661
+ description:"Background process cannot write to terminal output",
5662
+ standard:"posix"
5663
+ },
5664
+ {
5665
+ name:"SIGURG",
5666
+ number:23,
5667
+ action:"ignore",
5668
+ description:"Socket received out-of-band data",
5669
+ standard:"bsd"
5670
+ },
5671
+ {
5672
+ name:"SIGXCPU",
5673
+ number:24,
5674
+ action:"core",
5675
+ description:"Process timed out",
5676
+ standard:"bsd"
5677
+ },
5678
+ {
5679
+ name:"SIGXFSZ",
5680
+ number:25,
5681
+ action:"core",
5682
+ description:"File too big",
5683
+ standard:"bsd"
5684
+ },
5685
+ {
5686
+ name:"SIGVTALRM",
5687
+ number:26,
5688
+ action:"terminate",
5689
+ description:"Timeout or timer",
5690
+ standard:"bsd"
5691
+ },
5692
+ {
5693
+ name:"SIGPROF",
5694
+ number:27,
5695
+ action:"terminate",
5696
+ description:"Timeout or timer",
5697
+ standard:"bsd"
5698
+ },
5699
+ {
5700
+ name:"SIGWINCH",
5701
+ number:28,
5702
+ action:"ignore",
5703
+ description:"Terminal window size changed",
5704
+ standard:"bsd"
5705
+ },
5706
+ {
5707
+ name:"SIGIO",
5708
+ number:29,
5709
+ action:"terminate",
5710
+ description:"I/O is available",
5711
+ standard:"other"
5712
+ },
5713
+ {
5714
+ name:"SIGPOLL",
5715
+ number:29,
5716
+ action:"terminate",
5717
+ description:"Watched event",
5718
+ standard:"other"
5719
+ },
5720
+ {
5721
+ name:"SIGINFO",
5722
+ number:29,
5723
+ action:"ignore",
5724
+ description:"Request for process information",
5725
+ standard:"other"
5726
+ },
5727
+ {
5728
+ name:"SIGPWR",
5729
+ number:30,
5730
+ action:"terminate",
5731
+ description:"Device running out of power",
5732
+ standard:"systemv"
5733
+ },
5734
+ {
5735
+ name:"SIGSYS",
5736
+ number:31,
5737
+ action:"core",
5738
+ description:"Invalid system call",
5739
+ standard:"other"
5740
+ },
5741
+ {
5742
+ name:"SIGUNUSED",
5743
+ number:31,
5744
+ action:"terminate",
5745
+ description:"Invalid system call",
5746
+ standard:"other"
5747
+ }];
5748
+
5749
+ const getSignals=()=>{
5750
+ const realtimeSignals=getRealtimeSignals();
5751
+ const signals=[...SIGNALS,...realtimeSignals].map(normalizeSignal$1);
5752
+ return signals
5753
+ };
5754
+
5755
+
5756
+
5757
+
5758
+
5759
+
5760
+
5761
+ const normalizeSignal$1=({
5762
+ name,
5763
+ number:defaultNumber,
5764
+ description,
5765
+ action,
5766
+ forced=false,
5767
+ standard
5768
+ })=>{
5769
+ const{
5770
+ signals:{[name]:constantSignal}
5771
+ }=node_os.constants;
5772
+ const supported=constantSignal!==undefined;
5773
+ const number=supported?constantSignal:defaultNumber;
5774
+ return {name,number,description,supported,action,forced,standard}
5775
+ };
5776
+
5777
+ const getSignalsByName=()=>{
5778
+ const signals=getSignals();
5779
+ return Object.fromEntries(signals.map(getSignalByName))
5780
+ };
5781
+
5782
+ const getSignalByName=({
5783
+ name,
5784
+ number,
5785
+ description,
5786
+ supported,
5787
+ action,
5788
+ forced,
5789
+ standard
5790
+ })=>[name,{name,number,description,supported,action,forced,standard}];
5791
+
5792
+ const signalsByName=getSignalsByName();
5793
+
5794
+
5795
+
5796
+
5797
+ const getSignalsByNumber=()=>{
5798
+ const signals=getSignals();
5799
+ const length=SIGRTMAX+1;
5800
+ const signalsA=Array.from({length},(value,number)=>
5801
+ getSignalByNumber(number,signals)
5802
+ );
5803
+ return Object.assign({},...signalsA)
5804
+ };
5805
+
5806
+ const getSignalByNumber=(number,signals)=>{
5807
+ const signal=findSignalByNumber(number,signals);
5808
+
5809
+ if(signal===undefined){
5810
+ return {}
5811
+ }
5812
+
5813
+ const{name,description,supported,action,forced,standard}=signal;
5814
+ return {
5815
+ [number]:{
5816
+ name,
5817
+ number,
5818
+ description,
5819
+ supported,
5820
+ action,
5821
+ forced,
5822
+ standard
5823
+ }
5824
+ }
5825
+ };
5826
+
5827
+
5828
+
5829
+ const findSignalByNumber=(number,signals)=>{
5830
+ const signal=signals.find(({name})=>node_os.constants.signals[name]===number);
5831
+
5832
+ if(signal!==undefined){
5833
+ return signal
5834
+ }
5835
+
5836
+ return signals.find((signalA)=>signalA.number===number)
5837
+ };
5838
+
5839
+ getSignalsByNumber();
5840
+
5445
5841
  // Normalize signals for comparison purpose.
5446
5842
  // Also validate the signal exists.
5447
5843
  const normalizeKillSignal = killSignal => {
@@ -5450,14 +5846,14 @@ const normalizeKillSignal = killSignal => {
5450
5846
  throw new TypeError(`Invalid ${optionName}: 0 cannot be used.`);
5451
5847
  }
5452
5848
 
5453
- return normalizeSignal$1(killSignal, optionName);
5849
+ return normalizeSignal(killSignal, optionName);
5454
5850
  };
5455
5851
 
5456
5852
  const normalizeSignalArgument = signal => signal === 0
5457
5853
  ? signal
5458
- : normalizeSignal$1(signal, '`subprocess.kill()`\'s argument');
5854
+ : normalizeSignal(signal, '`subprocess.kill()`\'s argument');
5459
5855
 
5460
- const normalizeSignal$1 = (signalNameOrInteger, optionName) => {
5856
+ const normalizeSignal = (signalNameOrInteger, optionName) => {
5461
5857
  if (Number.isInteger(signalNameOrInteger)) {
5462
5858
  return normalizeSignalInteger(signalNameOrInteger, optionName);
5463
5859
  }
@@ -5507,6 +5903,9 @@ const getAvailableSignalIntegers = () => [...new Set(Object.values(node_os.const
5507
5903
  .sort((signalInteger, signalIntegerTwo) => signalInteger - signalIntegerTwo))]
5508
5904
  .join(', ');
5509
5905
 
5906
+ // Human-friendly description of a signal
5907
+ const getSignalDescription = signal => signalsByName[signal].description;
5908
+
5510
5909
  // Normalize the `forceKillAfterDelay` option
5511
5910
  const normalizeForceKillAfterDelay = forceKillAfterDelay => {
5512
5911
  if (forceKillAfterDelay === false) {
@@ -5528,7 +5927,7 @@ const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;
5528
5927
 
5529
5928
  // Monkey-patches `subprocess.kill()` to add `forceKillAfterDelay` behavior and `.kill(error)`
5530
5929
  const subprocessKill = (
5531
- {kill, options: {forceKillAfterDelay, killSignal}, onInternalError, controller},
5930
+ {kill, options: {forceKillAfterDelay, killSignal}, onInternalError, context, controller},
5532
5931
  signalOrError,
5533
5932
  errorArgument,
5534
5933
  ) => {
@@ -5541,6 +5940,7 @@ const subprocessKill = (
5541
5940
  forceKillAfterDelay,
5542
5941
  killSignal,
5543
5942
  killResult,
5943
+ context,
5544
5944
  controller,
5545
5945
  });
5546
5946
  return killResult;
@@ -5571,20 +5971,834 @@ const emitKillError = (error, onInternalError) => {
5571
5971
  }
5572
5972
  };
5573
5973
 
5574
- const setKillTimeout = async ({kill, signal, forceKillAfterDelay, killSignal, killResult, controller}) => {
5575
- if (!shouldForceKill(signal, forceKillAfterDelay, killSignal, killResult)) {
5974
+ const setKillTimeout = async ({kill, signal, forceKillAfterDelay, killSignal, killResult, context, controller}) => {
5975
+ if (signal === killSignal && killResult) {
5976
+ killOnTimeout({
5977
+ kill,
5978
+ forceKillAfterDelay,
5979
+ context,
5980
+ controllerSignal: controller.signal,
5981
+ });
5982
+ }
5983
+ };
5984
+
5985
+ // Forcefully terminate a subprocess after a timeout
5986
+ const killOnTimeout = async ({kill, forceKillAfterDelay, context, controllerSignal}) => {
5987
+ if (forceKillAfterDelay === false) {
5576
5988
  return;
5577
5989
  }
5578
5990
 
5579
5991
  try {
5580
- await promises.setTimeout(forceKillAfterDelay, undefined, {signal: controller.signal});
5581
- kill('SIGKILL');
5992
+ await promises.setTimeout(forceKillAfterDelay, undefined, {signal: controllerSignal});
5993
+ if (kill('SIGKILL')) {
5994
+ context.isForcefullyTerminated ??= true;
5995
+ }
5582
5996
  } catch {}
5583
5997
  };
5584
5998
 
5585
- const shouldForceKill = (signal, forceKillAfterDelay, killSignal, killResult) => signal === killSignal
5586
- && forceKillAfterDelay !== false
5587
- && killResult;
5999
+ // Combines `util.aborted()` and `events.addAbortListener()`: promise-based and cleaned up with a stop signal
6000
+ const onAbortedSignal = async (mainSignal, stopSignal) => {
6001
+ if (!mainSignal.aborted) {
6002
+ await require$$0.once(mainSignal, 'abort', {signal: stopSignal});
6003
+ }
6004
+ };
6005
+
6006
+ // Validate the `cancelSignal` option
6007
+ const validateCancelSignal = ({cancelSignal}) => {
6008
+ if (cancelSignal !== undefined && Object.prototype.toString.call(cancelSignal) !== '[object AbortSignal]') {
6009
+ throw new Error(`The \`cancelSignal\` option must be an AbortSignal: ${String(cancelSignal)}`);
6010
+ }
6011
+ };
6012
+
6013
+ // Terminate the subprocess when aborting the `cancelSignal` option and `gracefulSignal` is `false`
6014
+ const throwOnCancel = ({subprocess, cancelSignal, gracefulCancel, context, controller}) => cancelSignal === undefined || gracefulCancel
6015
+ ? []
6016
+ : [terminateOnCancel(subprocess, cancelSignal, context, controller)];
6017
+
6018
+ const terminateOnCancel = async (subprocess, cancelSignal, context, {signal}) => {
6019
+ await onAbortedSignal(cancelSignal, signal);
6020
+ context.terminationReason ??= 'cancel';
6021
+ subprocess.kill();
6022
+ throw cancelSignal.reason;
6023
+ };
6024
+
6025
+ // Validate the IPC channel is connected before receiving/sending messages
6026
+ const validateIpcMethod = ({methodName, isSubprocess, ipc, isConnected}) => {
6027
+ validateIpcOption(methodName, isSubprocess, ipc);
6028
+ validateConnection(methodName, isSubprocess, isConnected);
6029
+ };
6030
+
6031
+ // Better error message when forgetting to set `ipc: true` and using the IPC methods
6032
+ const validateIpcOption = (methodName, isSubprocess, ipc) => {
6033
+ if (!ipc) {
6034
+ throw new Error(`${getMethodName(methodName, isSubprocess)} can only be used if the \`ipc\` option is \`true\`.`);
6035
+ }
6036
+ };
6037
+
6038
+ // Better error message when one process does not send/receive messages once the other process has disconnected.
6039
+ // This also makes it clear that any buffered messages are lost once either process has disconnected.
6040
+ // Also when aborting `cancelSignal` after disconnecting the IPC.
6041
+ const validateConnection = (methodName, isSubprocess, isConnected) => {
6042
+ if (!isConnected) {
6043
+ throw new Error(`${getMethodName(methodName, isSubprocess)} cannot be used: the ${getOtherProcessName(isSubprocess)} has already exited or disconnected.`);
6044
+ }
6045
+ };
6046
+
6047
+ // When `getOneMessage()` could not complete due to an early disconnection
6048
+ const throwOnEarlyDisconnect = isSubprocess => {
6049
+ throw new Error(`${getMethodName('getOneMessage', isSubprocess)} could not complete: the ${getOtherProcessName(isSubprocess)} exited or disconnected.`);
6050
+ };
6051
+
6052
+ // When both processes use `sendMessage()` with `strict` at the same time
6053
+ const throwOnStrictDeadlockError = isSubprocess => {
6054
+ throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} is sending a message too, instead of listening to incoming messages.
6055
+ This can be fixed by both sending a message and listening to incoming messages at the same time:
6056
+
6057
+ const [receivedMessage] = await Promise.all([
6058
+ ${getMethodName('getOneMessage', isSubprocess)},
6059
+ ${getMethodName('sendMessage', isSubprocess, 'message, {strict: true}')},
6060
+ ]);`);
6061
+ };
6062
+
6063
+ // When the other process used `strict` but the current process had I/O error calling `sendMessage()` for the response
6064
+ const getStrictResponseError = (error, isSubprocess) => new Error(`${getMethodName('sendMessage', isSubprocess)} failed when sending an acknowledgment response to the ${getOtherProcessName(isSubprocess)}.`, {cause: error});
6065
+
6066
+ // When using `strict` but the other process was not listening for messages
6067
+ const throwOnMissingStrict = isSubprocess => {
6068
+ throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} is not listening to incoming messages.`);
6069
+ };
6070
+
6071
+ // When using `strict` but the other process disconnected before receiving the message
6072
+ const throwOnStrictDisconnect = isSubprocess => {
6073
+ throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} exited without listening to incoming messages.`);
6074
+ };
6075
+
6076
+ // When the current process disconnects while the subprocess is listening to `cancelSignal`
6077
+ const getAbortDisconnectError = () => new Error(`\`cancelSignal\` aborted: the ${getOtherProcessName(true)} disconnected.`);
6078
+
6079
+ // When the subprocess uses `cancelSignal` but not the current process
6080
+ const throwOnMissingParent = () => {
6081
+ throw new Error('`getCancelSignal()` cannot be used without setting the `cancelSignal` subprocess option.');
6082
+ };
6083
+
6084
+ // EPIPE can happen when sending a message to a subprocess that is closing but has not disconnected yet
6085
+ const handleEpipeError = ({error, methodName, isSubprocess}) => {
6086
+ if (error.code === 'EPIPE') {
6087
+ throw new Error(`${getMethodName(methodName, isSubprocess)} cannot be used: the ${getOtherProcessName(isSubprocess)} is disconnecting.`, {cause: error});
6088
+ }
6089
+ };
6090
+
6091
+ // Better error message when sending messages which cannot be serialized.
6092
+ // Works with both `serialization: 'advanced'` and `serialization: 'json'`.
6093
+ const handleSerializationError = ({error, methodName, isSubprocess, message}) => {
6094
+ if (isSerializationError(error)) {
6095
+ throw new Error(`${getMethodName(methodName, isSubprocess)}'s argument type is invalid: the message cannot be serialized: ${String(message)}.`, {cause: error});
6096
+ }
6097
+ };
6098
+
6099
+ const isSerializationError = ({code, message}) => SERIALIZATION_ERROR_CODES.has(code)
6100
+ || SERIALIZATION_ERROR_MESSAGES.some(serializationErrorMessage => message.includes(serializationErrorMessage));
6101
+
6102
+ // `error.code` set by Node.js when it failed to serialize the message
6103
+ const SERIALIZATION_ERROR_CODES = new Set([
6104
+ // Message is `undefined`
6105
+ 'ERR_MISSING_ARGS',
6106
+ // Message is a function, a bigint, a symbol
6107
+ 'ERR_INVALID_ARG_TYPE',
6108
+ ]);
6109
+
6110
+ // `error.message` set by Node.js when it failed to serialize the message
6111
+ const SERIALIZATION_ERROR_MESSAGES = [
6112
+ // Message is a promise or a proxy, with `serialization: 'advanced'`
6113
+ 'could not be cloned',
6114
+ // Message has cycles, with `serialization: 'json'`
6115
+ 'circular structure',
6116
+ // Message has cycles inside toJSON(), with `serialization: 'json'`
6117
+ 'call stack size exceeded',
6118
+ ];
6119
+
6120
+ const getMethodName = (methodName, isSubprocess, parameters = '') => methodName === 'cancelSignal'
6121
+ ? '`cancelSignal`\'s `controller.abort()`'
6122
+ : `${getNamespaceName(isSubprocess)}${methodName}(${parameters})`;
6123
+
6124
+ const getNamespaceName = isSubprocess => isSubprocess ? '' : 'subprocess.';
6125
+
6126
+ const getOtherProcessName = isSubprocess => isSubprocess ? 'parent process' : 'subprocess';
6127
+
6128
+ // When any error arises, we disconnect the IPC.
6129
+ // Otherwise, it is likely that one of the processes will stop sending/receiving messages.
6130
+ // This would leave the other process hanging.
6131
+ const disconnect = anyProcess => {
6132
+ if (anyProcess.connected) {
6133
+ anyProcess.disconnect();
6134
+ }
6135
+ };
6136
+
6137
+ const createDeferred = () => {
6138
+ const methods = {};
6139
+ const promise = new Promise((resolve, reject) => {
6140
+ Object.assign(methods, {resolve, reject});
6141
+ });
6142
+ return Object.assign(promise, methods);
6143
+ };
6144
+
6145
+ // Retrieve stream targeted by the `to` option
6146
+ const getToStream = (destination, to = 'stdin') => {
6147
+ const isWritable = true;
6148
+ const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(destination);
6149
+ const fdNumber = getFdNumber(fileDescriptors, to, isWritable);
6150
+ const destinationStream = destination.stdio[fdNumber];
6151
+
6152
+ if (destinationStream === null) {
6153
+ throw new TypeError(getInvalidStdioOptionMessage(fdNumber, to, options, isWritable));
6154
+ }
6155
+
6156
+ return destinationStream;
6157
+ };
6158
+
6159
+ // Retrieve stream targeted by the `from` option
6160
+ const getFromStream = (source, from = 'stdout') => {
6161
+ const isWritable = false;
6162
+ const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(source);
6163
+ const fdNumber = getFdNumber(fileDescriptors, from, isWritable);
6164
+ const sourceStream = fdNumber === 'all' ? source.all : source.stdio[fdNumber];
6165
+
6166
+ if (sourceStream === null || sourceStream === undefined) {
6167
+ throw new TypeError(getInvalidStdioOptionMessage(fdNumber, from, options, isWritable));
6168
+ }
6169
+
6170
+ return sourceStream;
6171
+ };
6172
+
6173
+ // Keeps track of the options passed to each Execa call
6174
+ const SUBPROCESS_OPTIONS = new WeakMap();
6175
+
6176
+ const getFdNumber = (fileDescriptors, fdName, isWritable) => {
6177
+ const fdNumber = parseFdNumber(fdName, isWritable);
6178
+ validateFdNumber(fdNumber, fdName, isWritable, fileDescriptors);
6179
+ return fdNumber;
6180
+ };
6181
+
6182
+ const parseFdNumber = (fdName, isWritable) => {
6183
+ const fdNumber = parseFd(fdName);
6184
+ if (fdNumber !== undefined) {
6185
+ return fdNumber;
6186
+ }
6187
+
6188
+ const {validOptions, defaultValue} = isWritable
6189
+ ? {validOptions: '"stdin"', defaultValue: 'stdin'}
6190
+ : {validOptions: '"stdout", "stderr", "all"', defaultValue: 'stdout'};
6191
+ throw new TypeError(`"${getOptionName(isWritable)}" must not be "${fdName}".
6192
+ It must be ${validOptions} or "fd3", "fd4" (and so on).
6193
+ It is optional and defaults to "${defaultValue}".`);
6194
+ };
6195
+
6196
+ const validateFdNumber = (fdNumber, fdName, isWritable, fileDescriptors) => {
6197
+ const fileDescriptor = fileDescriptors[getUsedDescriptor(fdNumber)];
6198
+ if (fileDescriptor === undefined) {
6199
+ throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. That file descriptor does not exist.
6200
+ Please set the "stdio" option to ensure that file descriptor exists.`);
6201
+ }
6202
+
6203
+ if (fileDescriptor.direction === 'input' && !isWritable) {
6204
+ throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a readable stream, not writable.`);
6205
+ }
6206
+
6207
+ if (fileDescriptor.direction !== 'input' && isWritable) {
6208
+ throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a writable stream, not readable.`);
6209
+ }
6210
+ };
6211
+
6212
+ const getInvalidStdioOptionMessage = (fdNumber, fdName, options, isWritable) => {
6213
+ if (fdNumber === 'all' && !options.all) {
6214
+ return 'The "all" option must be true to use "from: \'all\'".';
6215
+ }
6216
+
6217
+ const {optionName, optionValue} = getInvalidStdioOption(fdNumber, options);
6218
+ return `The "${optionName}: ${serializeOptionValue(optionValue)}" option is incompatible with using "${getOptionName(isWritable)}: ${serializeOptionValue(fdName)}".
6219
+ Please set this option with "pipe" instead.`;
6220
+ };
6221
+
6222
+ const getInvalidStdioOption = (fdNumber, {stdin, stdout, stderr, stdio}) => {
6223
+ const usedDescriptor = getUsedDescriptor(fdNumber);
6224
+
6225
+ if (usedDescriptor === 0 && stdin !== undefined) {
6226
+ return {optionName: 'stdin', optionValue: stdin};
6227
+ }
6228
+
6229
+ if (usedDescriptor === 1 && stdout !== undefined) {
6230
+ return {optionName: 'stdout', optionValue: stdout};
6231
+ }
6232
+
6233
+ if (usedDescriptor === 2 && stderr !== undefined) {
6234
+ return {optionName: 'stderr', optionValue: stderr};
6235
+ }
6236
+
6237
+ return {optionName: `stdio[${usedDescriptor}]`, optionValue: stdio[usedDescriptor]};
6238
+ };
6239
+
6240
+ const getUsedDescriptor = fdNumber => fdNumber === 'all' ? 1 : fdNumber;
6241
+
6242
+ const getOptionName = isWritable => isWritable ? 'to' : 'from';
6243
+
6244
+ const serializeOptionValue = value => {
6245
+ if (typeof value === 'string') {
6246
+ return `'${value}'`;
6247
+ }
6248
+
6249
+ return typeof value === 'number' ? `${value}` : 'Stream';
6250
+ };
6251
+
6252
+ // Temporarily increase the maximum number of listeners on an eventEmitter
6253
+ const incrementMaxListeners = (eventEmitter, maxListenersIncrement, signal) => {
6254
+ const maxListeners = eventEmitter.getMaxListeners();
6255
+ if (maxListeners === 0 || maxListeners === Number.POSITIVE_INFINITY) {
6256
+ return;
6257
+ }
6258
+
6259
+ eventEmitter.setMaxListeners(maxListeners + maxListenersIncrement);
6260
+ require$$0.addAbortListener(signal, () => {
6261
+ eventEmitter.setMaxListeners(eventEmitter.getMaxListeners() - maxListenersIncrement);
6262
+ });
6263
+ };
6264
+
6265
+ // By default, Node.js keeps the subprocess alive while it has a `message` or `disconnect` listener.
6266
+ // We replicate the same logic for the events that we proxy.
6267
+ // This ensures the subprocess is kept alive while `getOneMessage()` and `getEachMessage()` are ongoing.
6268
+ // This is not a problem with `sendMessage()` since Node.js handles that method automatically.
6269
+ // We do not use `anyProcess.channel.ref()` since this would prevent the automatic `.channel.refCounted()` Node.js is doing.
6270
+ // We keep a reference to `anyProcess.channel` since it might be `null` while `getOneMessage()` or `getEachMessage()` is still processing debounced messages.
6271
+ // See https://github.com/nodejs/node/blob/2aaeaa863c35befa2ebaa98fb7737ec84df4d8e9/lib/internal/child_process.js#L547
6272
+ const addReference = (channel, reference) => {
6273
+ if (reference) {
6274
+ addReferenceCount(channel);
6275
+ }
6276
+ };
6277
+
6278
+ const addReferenceCount = channel => {
6279
+ channel.refCounted();
6280
+ };
6281
+
6282
+ const removeReference = (channel, reference) => {
6283
+ if (reference) {
6284
+ removeReferenceCount(channel);
6285
+ }
6286
+ };
6287
+
6288
+ const removeReferenceCount = channel => {
6289
+ channel.unrefCounted();
6290
+ };
6291
+
6292
+ // To proxy events, we setup some global listeners on the `message` and `disconnect` events.
6293
+ // Those should not keep the subprocess alive, so we remove the automatic counting that Node.js is doing.
6294
+ // See https://github.com/nodejs/node/blob/1b965270a9c273d4cf70e8808e9d28b9ada7844f/lib/child_process.js#L180
6295
+ const undoAddedReferences = (channel, isSubprocess) => {
6296
+ if (isSubprocess) {
6297
+ removeReferenceCount(channel);
6298
+ removeReferenceCount(channel);
6299
+ }
6300
+ };
6301
+
6302
+ // Reverse it during `disconnect`
6303
+ const redoAddedReferences = (channel, isSubprocess) => {
6304
+ if (isSubprocess) {
6305
+ addReferenceCount(channel);
6306
+ addReferenceCount(channel);
6307
+ }
6308
+ };
6309
+
6310
+ // By default, Node.js buffers `message` events.
6311
+ // - Buffering happens when there is a `message` event is emitted but there is no handler.
6312
+ // - As soon as a `message` event handler is set, all buffered `message` events are emitted, emptying the buffer.
6313
+ // - This happens both in the current process and the subprocess.
6314
+ // - See https://github.com/nodejs/node/blob/501546e8f37059cd577041e23941b640d0d4d406/lib/internal/child_process.js#L719
6315
+ // This is helpful. Notably, this allows sending messages to a subprocess that's still initializing.
6316
+ // However, it has several problems.
6317
+ // - This works with `events.on()` but not `events.once()` since all buffered messages are emitted at once.
6318
+ // For example, users cannot call `await getOneMessage()`/`getEachMessage()` multiple times in a row.
6319
+ // - When a user intentionally starts listening to `message` at a specific point in time, past `message` events are replayed, which might be unexpected.
6320
+ // - Buffering is unlimited, which might lead to an out-of-memory crash.
6321
+ // - This does not work well with multiple consumers.
6322
+ // For example, Execa consumes events with both `result.ipcOutput` and manual IPC calls like `getOneMessage()`.
6323
+ // Since `result.ipcOutput` reads all incoming messages, no buffering happens for manual IPC calls.
6324
+ // - Forgetting to setup a `message` listener, or setting it up too late, is a programming mistake.
6325
+ // The default behavior does not allow users to realize they made that mistake.
6326
+ // To solve those problems, instead of buffering messages, we debounce them.
6327
+ // The `message` event so it is emitted at most once per macrotask.
6328
+ const onMessage = async ({anyProcess, channel, isSubprocess, ipcEmitter}, wrappedMessage) => {
6329
+ if (handleStrictResponse(wrappedMessage) || handleAbort(wrappedMessage)) {
6330
+ return;
6331
+ }
6332
+
6333
+ if (!INCOMING_MESSAGES.has(anyProcess)) {
6334
+ INCOMING_MESSAGES.set(anyProcess, []);
6335
+ }
6336
+
6337
+ const incomingMessages = INCOMING_MESSAGES.get(anyProcess);
6338
+ incomingMessages.push(wrappedMessage);
6339
+
6340
+ if (incomingMessages.length > 1) {
6341
+ return;
6342
+ }
6343
+
6344
+ while (incomingMessages.length > 0) {
6345
+ // eslint-disable-next-line no-await-in-loop
6346
+ await waitForOutgoingMessages(anyProcess, ipcEmitter, wrappedMessage);
6347
+ // eslint-disable-next-line no-await-in-loop
6348
+ await promises.scheduler.yield();
6349
+
6350
+ // eslint-disable-next-line no-await-in-loop
6351
+ const message = await handleStrictRequest({
6352
+ wrappedMessage: incomingMessages[0],
6353
+ anyProcess,
6354
+ channel,
6355
+ isSubprocess,
6356
+ ipcEmitter,
6357
+ });
6358
+
6359
+ incomingMessages.shift();
6360
+ ipcEmitter.emit('message', message);
6361
+ ipcEmitter.emit('message:done');
6362
+ }
6363
+ };
6364
+
6365
+ // If the `message` event is currently debounced, the `disconnect` event must wait for it
6366
+ const onDisconnect = async ({anyProcess, channel, isSubprocess, ipcEmitter, boundOnMessage}) => {
6367
+ abortOnDisconnect();
6368
+
6369
+ const incomingMessages = INCOMING_MESSAGES.get(anyProcess);
6370
+ while (incomingMessages?.length > 0) {
6371
+ // eslint-disable-next-line no-await-in-loop
6372
+ await require$$0.once(ipcEmitter, 'message:done');
6373
+ }
6374
+
6375
+ anyProcess.removeListener('message', boundOnMessage);
6376
+ redoAddedReferences(channel, isSubprocess);
6377
+ ipcEmitter.connected = false;
6378
+ ipcEmitter.emit('disconnect');
6379
+ };
6380
+
6381
+ const INCOMING_MESSAGES = new WeakMap();
6382
+
6383
+ // Forward the `message` and `disconnect` events from the process and subprocess to a proxy emitter.
6384
+ // This prevents the `error` event from stopping IPC.
6385
+ // This also allows debouncing the `message` event.
6386
+ const getIpcEmitter = (anyProcess, channel, isSubprocess) => {
6387
+ if (IPC_EMITTERS.has(anyProcess)) {
6388
+ return IPC_EMITTERS.get(anyProcess);
6389
+ }
6390
+
6391
+ // Use an `EventEmitter`, like the `process` that is being proxied
6392
+ // eslint-disable-next-line unicorn/prefer-event-target
6393
+ const ipcEmitter = new require$$0.EventEmitter();
6394
+ ipcEmitter.connected = true;
6395
+ IPC_EMITTERS.set(anyProcess, ipcEmitter);
6396
+ forwardEvents({
6397
+ ipcEmitter,
6398
+ anyProcess,
6399
+ channel,
6400
+ isSubprocess,
6401
+ });
6402
+ return ipcEmitter;
6403
+ };
6404
+
6405
+ const IPC_EMITTERS = new WeakMap();
6406
+
6407
+ // The `message` and `disconnect` events are buffered in the subprocess until the first listener is setup.
6408
+ // However, unbuffering happens after one tick, so this give enough time for the caller to setup the listener on the proxy emitter first.
6409
+ // See https://github.com/nodejs/node/blob/2aaeaa863c35befa2ebaa98fb7737ec84df4d8e9/lib/internal/child_process.js#L721
6410
+ const forwardEvents = ({ipcEmitter, anyProcess, channel, isSubprocess}) => {
6411
+ const boundOnMessage = onMessage.bind(undefined, {
6412
+ anyProcess,
6413
+ channel,
6414
+ isSubprocess,
6415
+ ipcEmitter,
6416
+ });
6417
+ anyProcess.on('message', boundOnMessage);
6418
+ anyProcess.once('disconnect', onDisconnect.bind(undefined, {
6419
+ anyProcess,
6420
+ channel,
6421
+ isSubprocess,
6422
+ ipcEmitter,
6423
+ boundOnMessage,
6424
+ }));
6425
+ undoAddedReferences(channel, isSubprocess);
6426
+ };
6427
+
6428
+ // Check whether there might still be some `message` events to receive
6429
+ const isConnected = anyProcess => {
6430
+ const ipcEmitter = IPC_EMITTERS.get(anyProcess);
6431
+ return ipcEmitter === undefined
6432
+ ? anyProcess.channel !== null
6433
+ : ipcEmitter.connected;
6434
+ };
6435
+
6436
+ // When using the `strict` option, wrap the message with metadata during `sendMessage()`
6437
+ const handleSendStrict = ({anyProcess, channel, isSubprocess, message, strict}) => {
6438
+ if (!strict) {
6439
+ return message;
6440
+ }
6441
+
6442
+ const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
6443
+ const hasListeners = hasMessageListeners(anyProcess, ipcEmitter);
6444
+ return {
6445
+ id: count++,
6446
+ type: REQUEST_TYPE,
6447
+ message,
6448
+ hasListeners,
6449
+ };
6450
+ };
6451
+
6452
+ let count = 0n;
6453
+
6454
+ // Handles when both processes are calling `sendMessage()` with `strict` at the same time.
6455
+ // If neither process is listening, this would create a deadlock. We detect it and throw.
6456
+ const validateStrictDeadlock = (outgoingMessages, wrappedMessage) => {
6457
+ if (wrappedMessage?.type !== REQUEST_TYPE || wrappedMessage.hasListeners) {
6458
+ return;
6459
+ }
6460
+
6461
+ for (const {id} of outgoingMessages) {
6462
+ if (id !== undefined) {
6463
+ STRICT_RESPONSES[id].resolve({isDeadlock: true, hasListeners: false});
6464
+ }
6465
+ }
6466
+ };
6467
+
6468
+ // The other process then sends the acknowledgment back as a response
6469
+ const handleStrictRequest = async ({wrappedMessage, anyProcess, channel, isSubprocess, ipcEmitter}) => {
6470
+ if (wrappedMessage?.type !== REQUEST_TYPE || !anyProcess.connected) {
6471
+ return wrappedMessage;
6472
+ }
6473
+
6474
+ const {id, message} = wrappedMessage;
6475
+ const response = {id, type: RESPONSE_TYPE, message: hasMessageListeners(anyProcess, ipcEmitter)};
6476
+
6477
+ try {
6478
+ await sendMessage({
6479
+ anyProcess,
6480
+ channel,
6481
+ isSubprocess,
6482
+ ipc: true,
6483
+ }, response);
6484
+ } catch (error) {
6485
+ ipcEmitter.emit('strict:error', error);
6486
+ }
6487
+
6488
+ return message;
6489
+ };
6490
+
6491
+ // Reception of the acknowledgment response
6492
+ const handleStrictResponse = wrappedMessage => {
6493
+ if (wrappedMessage?.type !== RESPONSE_TYPE) {
6494
+ return false;
6495
+ }
6496
+
6497
+ const {id, message: hasListeners} = wrappedMessage;
6498
+ STRICT_RESPONSES[id]?.resolve({isDeadlock: false, hasListeners});
6499
+ return true;
6500
+ };
6501
+
6502
+ // Wait for the other process to receive the message from `sendMessage()`
6503
+ const waitForStrictResponse = async (wrappedMessage, anyProcess, isSubprocess) => {
6504
+ if (wrappedMessage?.type !== REQUEST_TYPE) {
6505
+ return;
6506
+ }
6507
+
6508
+ const deferred = createDeferred();
6509
+ STRICT_RESPONSES[wrappedMessage.id] = deferred;
6510
+ const controller = new AbortController();
6511
+
6512
+ try {
6513
+ const {isDeadlock, hasListeners} = await Promise.race([
6514
+ deferred,
6515
+ throwOnDisconnect$1(anyProcess, isSubprocess, controller),
6516
+ ]);
6517
+
6518
+ if (isDeadlock) {
6519
+ throwOnStrictDeadlockError(isSubprocess);
6520
+ }
6521
+
6522
+ if (!hasListeners) {
6523
+ throwOnMissingStrict(isSubprocess);
6524
+ }
6525
+ } finally {
6526
+ controller.abort();
6527
+ delete STRICT_RESPONSES[wrappedMessage.id];
6528
+ }
6529
+ };
6530
+
6531
+ const STRICT_RESPONSES = {};
6532
+
6533
+ const throwOnDisconnect$1 = async (anyProcess, isSubprocess, {signal}) => {
6534
+ incrementMaxListeners(anyProcess, 1, signal);
6535
+ await require$$0.once(anyProcess, 'disconnect', {signal});
6536
+ throwOnStrictDisconnect(isSubprocess);
6537
+ };
6538
+
6539
+ const REQUEST_TYPE = 'execa:ipc:request';
6540
+ const RESPONSE_TYPE = 'execa:ipc:response';
6541
+
6542
+ // When `sendMessage()` is ongoing, any `message` being received waits before being emitted.
6543
+ // This allows calling one or multiple `await sendMessage()` followed by `await getOneMessage()`/`await getEachMessage()`.
6544
+ // Without running into a race condition when the other process sends a response too fast, before the current process set up a listener.
6545
+ const startSendMessage = (anyProcess, wrappedMessage, strict) => {
6546
+ if (!OUTGOING_MESSAGES.has(anyProcess)) {
6547
+ OUTGOING_MESSAGES.set(anyProcess, new Set());
6548
+ }
6549
+
6550
+ const outgoingMessages = OUTGOING_MESSAGES.get(anyProcess);
6551
+ const onMessageSent = createDeferred();
6552
+ const id = strict ? wrappedMessage.id : undefined;
6553
+ const outgoingMessage = {onMessageSent, id};
6554
+ outgoingMessages.add(outgoingMessage);
6555
+ return {outgoingMessages, outgoingMessage};
6556
+ };
6557
+
6558
+ const endSendMessage = ({outgoingMessages, outgoingMessage}) => {
6559
+ outgoingMessages.delete(outgoingMessage);
6560
+ outgoingMessage.onMessageSent.resolve();
6561
+ };
6562
+
6563
+ // Await while `sendMessage()` is ongoing, unless there is already a `message` listener
6564
+ const waitForOutgoingMessages = async (anyProcess, ipcEmitter, wrappedMessage) => {
6565
+ while (!hasMessageListeners(anyProcess, ipcEmitter) && OUTGOING_MESSAGES.get(anyProcess)?.size > 0) {
6566
+ const outgoingMessages = [...OUTGOING_MESSAGES.get(anyProcess)];
6567
+ validateStrictDeadlock(outgoingMessages, wrappedMessage);
6568
+ // eslint-disable-next-line no-await-in-loop
6569
+ await Promise.all(outgoingMessages.map(({onMessageSent}) => onMessageSent));
6570
+ }
6571
+ };
6572
+
6573
+ const OUTGOING_MESSAGES = new WeakMap();
6574
+
6575
+ // Whether any `message` listener is setup
6576
+ const hasMessageListeners = (anyProcess, ipcEmitter) => ipcEmitter.listenerCount('message') > getMinListenerCount(anyProcess);
6577
+
6578
+ // When `buffer` is `false`, we set up a `message` listener that should be ignored.
6579
+ // That listener is only meant to intercept `strict` acknowledgement responses.
6580
+ const getMinListenerCount = anyProcess => SUBPROCESS_OPTIONS.has(anyProcess)
6581
+ && !SUBPROCESS_OPTIONS.get(anyProcess).options.buffer.at(-1)
6582
+ ? 1
6583
+ : 0;
6584
+
6585
+ // Like `[sub]process.send()` but promise-based.
6586
+ // We do not `await subprocess` during `.sendMessage()` nor `.getOneMessage()` since those methods are transient.
6587
+ // Users would still need to `await subprocess` after the method is done.
6588
+ // Also, this would prevent `unhandledRejection` event from being emitted, making it silent.
6589
+ const sendMessage = ({anyProcess, channel, isSubprocess, ipc}, message, {strict = false} = {}) => {
6590
+ const methodName = 'sendMessage';
6591
+ validateIpcMethod({
6592
+ methodName,
6593
+ isSubprocess,
6594
+ ipc,
6595
+ isConnected: anyProcess.connected,
6596
+ });
6597
+
6598
+ return sendMessageAsync({
6599
+ anyProcess,
6600
+ channel,
6601
+ methodName,
6602
+ isSubprocess,
6603
+ message,
6604
+ strict,
6605
+ });
6606
+ };
6607
+
6608
+ const sendMessageAsync = async ({anyProcess, channel, methodName, isSubprocess, message, strict}) => {
6609
+ const wrappedMessage = handleSendStrict({
6610
+ anyProcess,
6611
+ channel,
6612
+ isSubprocess,
6613
+ message,
6614
+ strict,
6615
+ });
6616
+ const outgoingMessagesState = startSendMessage(anyProcess, wrappedMessage, strict);
6617
+ try {
6618
+ await sendOneMessage({
6619
+ anyProcess,
6620
+ methodName,
6621
+ isSubprocess,
6622
+ wrappedMessage,
6623
+ message,
6624
+ });
6625
+ } catch (error) {
6626
+ disconnect(anyProcess);
6627
+ throw error;
6628
+ } finally {
6629
+ endSendMessage(outgoingMessagesState);
6630
+ }
6631
+ };
6632
+
6633
+ // Used internally by `cancelSignal`
6634
+ const sendOneMessage = async ({anyProcess, methodName, isSubprocess, wrappedMessage, message}) => {
6635
+ const sendMethod = getSendMethod(anyProcess);
6636
+
6637
+ try {
6638
+ await Promise.all([
6639
+ waitForStrictResponse(wrappedMessage, anyProcess, isSubprocess),
6640
+ sendMethod(wrappedMessage),
6641
+ ]);
6642
+ } catch (error) {
6643
+ handleEpipeError({error, methodName, isSubprocess});
6644
+ handleSerializationError({
6645
+ error,
6646
+ methodName,
6647
+ isSubprocess,
6648
+ message,
6649
+ });
6650
+ throw error;
6651
+ }
6652
+ };
6653
+
6654
+ // [sub]process.send() promisified, memoized
6655
+ const getSendMethod = anyProcess => {
6656
+ if (PROCESS_SEND_METHODS.has(anyProcess)) {
6657
+ return PROCESS_SEND_METHODS.get(anyProcess);
6658
+ }
6659
+
6660
+ const sendMethod = node_util.promisify(anyProcess.send.bind(anyProcess));
6661
+ PROCESS_SEND_METHODS.set(anyProcess, sendMethod);
6662
+ return sendMethod;
6663
+ };
6664
+
6665
+ const PROCESS_SEND_METHODS = new WeakMap();
6666
+
6667
+ // Send an IPC message so the subprocess performs a graceful termination
6668
+ const sendAbort = (subprocess, message) => {
6669
+ const methodName = 'cancelSignal';
6670
+ validateConnection(methodName, false, subprocess.connected);
6671
+ return sendOneMessage({
6672
+ anyProcess: subprocess,
6673
+ methodName,
6674
+ isSubprocess: false,
6675
+ wrappedMessage: {type: GRACEFUL_CANCEL_TYPE, message},
6676
+ message,
6677
+ });
6678
+ };
6679
+
6680
+ // When the signal is being used, start listening for incoming messages.
6681
+ // Unbuffering messages takes one microtask to complete, so this must be async.
6682
+ const getCancelSignal = async ({anyProcess, channel, isSubprocess, ipc}) => {
6683
+ await startIpc({
6684
+ anyProcess,
6685
+ channel,
6686
+ isSubprocess,
6687
+ ipc,
6688
+ });
6689
+ return cancelController.signal;
6690
+ };
6691
+
6692
+ const startIpc = async ({anyProcess, channel, isSubprocess, ipc}) => {
6693
+ if (cancelListening) {
6694
+ return;
6695
+ }
6696
+
6697
+ cancelListening = true;
6698
+
6699
+ if (!ipc) {
6700
+ throwOnMissingParent();
6701
+ return;
6702
+ }
6703
+
6704
+ if (channel === null) {
6705
+ abortOnDisconnect();
6706
+ return;
6707
+ }
6708
+
6709
+ getIpcEmitter(anyProcess, channel, isSubprocess);
6710
+ await promises.scheduler.yield();
6711
+ };
6712
+
6713
+ let cancelListening = false;
6714
+
6715
+ // Reception of IPC message to perform a graceful termination
6716
+ const handleAbort = wrappedMessage => {
6717
+ if (wrappedMessage?.type !== GRACEFUL_CANCEL_TYPE) {
6718
+ return false;
6719
+ }
6720
+
6721
+ cancelController.abort(wrappedMessage.message);
6722
+ return true;
6723
+ };
6724
+
6725
+ const GRACEFUL_CANCEL_TYPE = 'execa:ipc:cancel';
6726
+
6727
+ // When the current process disconnects early, the subprocess `cancelSignal` is aborted.
6728
+ // Otherwise, the signal would never be able to be aborted later on.
6729
+ const abortOnDisconnect = () => {
6730
+ cancelController.abort(getAbortDisconnectError());
6731
+ };
6732
+
6733
+ const cancelController = new AbortController();
6734
+
6735
+ // Validate the `gracefulCancel` option
6736
+ const validateGracefulCancel = ({gracefulCancel, cancelSignal, ipc, serialization}) => {
6737
+ if (!gracefulCancel) {
6738
+ return;
6739
+ }
6740
+
6741
+ if (cancelSignal === undefined) {
6742
+ throw new Error('The `cancelSignal` option must be defined when setting the `gracefulCancel` option.');
6743
+ }
6744
+
6745
+ if (!ipc) {
6746
+ throw new Error('The `ipc` option cannot be false when setting the `gracefulCancel` option.');
6747
+ }
6748
+
6749
+ if (serialization === 'json') {
6750
+ throw new Error('The `serialization` option cannot be \'json\' when setting the `gracefulCancel` option.');
6751
+ }
6752
+ };
6753
+
6754
+ // Send abort reason to the subprocess when aborting the `cancelSignal` option and `gracefulCancel` is `true`
6755
+ const throwOnGracefulCancel = ({
6756
+ subprocess,
6757
+ cancelSignal,
6758
+ gracefulCancel,
6759
+ forceKillAfterDelay,
6760
+ context,
6761
+ controller,
6762
+ }) => gracefulCancel
6763
+ ? [sendOnAbort({
6764
+ subprocess,
6765
+ cancelSignal,
6766
+ forceKillAfterDelay,
6767
+ context,
6768
+ controller,
6769
+ })]
6770
+ : [];
6771
+
6772
+ const sendOnAbort = async ({subprocess, cancelSignal, forceKillAfterDelay, context, controller: {signal}}) => {
6773
+ await onAbortedSignal(cancelSignal, signal);
6774
+ const reason = getReason(cancelSignal);
6775
+ await sendAbort(subprocess, reason);
6776
+ killOnTimeout({
6777
+ kill: subprocess.kill,
6778
+ forceKillAfterDelay,
6779
+ context,
6780
+ controllerSignal: signal,
6781
+ });
6782
+ context.terminationReason ??= 'gracefulCancel';
6783
+ throw cancelSignal.reason;
6784
+ };
6785
+
6786
+ // The default `reason` is a DOMException, which is not serializable with V8
6787
+ // See https://github.com/nodejs/node/issues/53225
6788
+ const getReason = ({reason}) => {
6789
+ if (!(reason instanceof DOMException)) {
6790
+ return reason;
6791
+ }
6792
+
6793
+ const error = new Error(reason.message);
6794
+ Object.defineProperty(error, 'stack', {
6795
+ value: reason.stack,
6796
+ enumerable: false,
6797
+ configurable: true,
6798
+ writable: true,
6799
+ });
6800
+ return error;
6801
+ };
5588
6802
 
5589
6803
  // Validate `timeout` option
5590
6804
  const validateTimeout = ({timeout}) => {
@@ -5600,7 +6814,7 @@ const throwOnTimeout = (subprocess, timeout, context, controller) => timeout ===
5600
6814
 
5601
6815
  const killAfterTimeout = async (subprocess, timeout, context, {signal}) => {
5602
6816
  await promises.setTimeout(timeout, undefined, {signal});
5603
- context.timedOut = true;
6817
+ context.terminationReason ??= 'timeout';
5604
6818
  subprocess.kill();
5605
6819
  throw new DiscardedError();
5606
6820
  };
@@ -5653,6 +6867,49 @@ const handleNodeOption = (file, commandArguments, {
5653
6867
  ];
5654
6868
  };
5655
6869
 
6870
+ // Validate the `ipcInput` option
6871
+ const validateIpcInputOption = ({ipcInput, ipc, serialization}) => {
6872
+ if (ipcInput === undefined) {
6873
+ return;
6874
+ }
6875
+
6876
+ if (!ipc) {
6877
+ throw new Error('The `ipcInput` option cannot be set unless the `ipc` option is `true`.');
6878
+ }
6879
+
6880
+ validateIpcInput[serialization](ipcInput);
6881
+ };
6882
+
6883
+ const validateAdvancedInput = ipcInput => {
6884
+ try {
6885
+ node_v8.serialize(ipcInput);
6886
+ } catch (error) {
6887
+ throw new Error('The `ipcInput` option is not serializable with a structured clone.', {cause: error});
6888
+ }
6889
+ };
6890
+
6891
+ const validateJsonInput = ipcInput => {
6892
+ try {
6893
+ JSON.stringify(ipcInput);
6894
+ } catch (error) {
6895
+ throw new Error('The `ipcInput` option is not serializable with JSON.', {cause: error});
6896
+ }
6897
+ };
6898
+
6899
+ const validateIpcInput = {
6900
+ advanced: validateAdvancedInput,
6901
+ json: validateJsonInput,
6902
+ };
6903
+
6904
+ // When the `ipcInput` option is set, it is sent as an initial IPC message to the subprocess
6905
+ const sendIpcInput = async (subprocess, ipcInput) => {
6906
+ if (ipcInput === undefined) {
6907
+ return;
6908
+ }
6909
+
6910
+ await subprocess.sendMessage(ipcInput);
6911
+ };
6912
+
5656
6913
  // Validate `encoding` option
5657
6914
  const validateEncoding = ({encoding}) => {
5658
6915
  if (ENCODINGS.has(encoding)) {
@@ -5751,6 +7008,9 @@ const normalizeOptions$2 = (filePath, rawArguments, rawOptions) => {
5751
7008
  const options = addDefaultOptions(fdOptions);
5752
7009
  validateTimeout(options);
5753
7010
  validateEncoding(options);
7011
+ validateIpcInputOption(options);
7012
+ validateCancelSignal(options);
7013
+ validateGracefulCancel(options);
5754
7014
  options.shell = normalizeFileUrl(options.shell);
5755
7015
  options.env = getEnv(options);
5756
7016
  options.killSignal = normalizeKillSignal(options.killSignal);
@@ -5777,7 +7037,9 @@ const addDefaultOptions = ({
5777
7037
  windowsHide = true,
5778
7038
  killSignal = 'SIGTERM',
5779
7039
  forceKillAfterDelay = true,
5780
- ipc = false,
7040
+ gracefulCancel = false,
7041
+ ipcInput,
7042
+ ipc = ipcInput !== undefined || gracefulCancel,
5781
7043
  serialization = 'advanced',
5782
7044
  ...options
5783
7045
  }) => ({
@@ -5793,6 +7055,8 @@ const addDefaultOptions = ({
5793
7055
  windowsHide,
5794
7056
  killSignal,
5795
7057
  forceKillAfterDelay,
7058
+ gracefulCancel,
7059
+ ipcInput,
5796
7060
  ipc,
5797
7061
  serialization,
5798
7062
  });
@@ -5813,386 +7077,6 @@ const getEnv = ({env: envOption, extendEnv, preferLocal, node, localDirectory, n
5813
7077
  return env;
5814
7078
  };
5815
7079
 
5816
- const getRealtimeSignals=()=>{
5817
- const length=SIGRTMAX-SIGRTMIN+1;
5818
- return Array.from({length},getRealtimeSignal)
5819
- };
5820
-
5821
- const getRealtimeSignal=(value,index)=>({
5822
- name:`SIGRT${index+1}`,
5823
- number:SIGRTMIN+index,
5824
- action:"terminate",
5825
- description:"Application-specific signal (realtime)",
5826
- standard:"posix"
5827
- });
5828
-
5829
- const SIGRTMIN=34;
5830
- const SIGRTMAX=64;
5831
-
5832
- const SIGNALS=[
5833
- {
5834
- name:"SIGHUP",
5835
- number:1,
5836
- action:"terminate",
5837
- description:"Terminal closed",
5838
- standard:"posix"
5839
- },
5840
- {
5841
- name:"SIGINT",
5842
- number:2,
5843
- action:"terminate",
5844
- description:"User interruption with CTRL-C",
5845
- standard:"ansi"
5846
- },
5847
- {
5848
- name:"SIGQUIT",
5849
- number:3,
5850
- action:"core",
5851
- description:"User interruption with CTRL-\\",
5852
- standard:"posix"
5853
- },
5854
- {
5855
- name:"SIGILL",
5856
- number:4,
5857
- action:"core",
5858
- description:"Invalid machine instruction",
5859
- standard:"ansi"
5860
- },
5861
- {
5862
- name:"SIGTRAP",
5863
- number:5,
5864
- action:"core",
5865
- description:"Debugger breakpoint",
5866
- standard:"posix"
5867
- },
5868
- {
5869
- name:"SIGABRT",
5870
- number:6,
5871
- action:"core",
5872
- description:"Aborted",
5873
- standard:"ansi"
5874
- },
5875
- {
5876
- name:"SIGIOT",
5877
- number:6,
5878
- action:"core",
5879
- description:"Aborted",
5880
- standard:"bsd"
5881
- },
5882
- {
5883
- name:"SIGBUS",
5884
- number:7,
5885
- action:"core",
5886
- description:
5887
- "Bus error due to misaligned, non-existing address or paging error",
5888
- standard:"bsd"
5889
- },
5890
- {
5891
- name:"SIGEMT",
5892
- number:7,
5893
- action:"terminate",
5894
- description:"Command should be emulated but is not implemented",
5895
- standard:"other"
5896
- },
5897
- {
5898
- name:"SIGFPE",
5899
- number:8,
5900
- action:"core",
5901
- description:"Floating point arithmetic error",
5902
- standard:"ansi"
5903
- },
5904
- {
5905
- name:"SIGKILL",
5906
- number:9,
5907
- action:"terminate",
5908
- description:"Forced termination",
5909
- standard:"posix",
5910
- forced:true
5911
- },
5912
- {
5913
- name:"SIGUSR1",
5914
- number:10,
5915
- action:"terminate",
5916
- description:"Application-specific signal",
5917
- standard:"posix"
5918
- },
5919
- {
5920
- name:"SIGSEGV",
5921
- number:11,
5922
- action:"core",
5923
- description:"Segmentation fault",
5924
- standard:"ansi"
5925
- },
5926
- {
5927
- name:"SIGUSR2",
5928
- number:12,
5929
- action:"terminate",
5930
- description:"Application-specific signal",
5931
- standard:"posix"
5932
- },
5933
- {
5934
- name:"SIGPIPE",
5935
- number:13,
5936
- action:"terminate",
5937
- description:"Broken pipe or socket",
5938
- standard:"posix"
5939
- },
5940
- {
5941
- name:"SIGALRM",
5942
- number:14,
5943
- action:"terminate",
5944
- description:"Timeout or timer",
5945
- standard:"posix"
5946
- },
5947
- {
5948
- name:"SIGTERM",
5949
- number:15,
5950
- action:"terminate",
5951
- description:"Termination",
5952
- standard:"ansi"
5953
- },
5954
- {
5955
- name:"SIGSTKFLT",
5956
- number:16,
5957
- action:"terminate",
5958
- description:"Stack is empty or overflowed",
5959
- standard:"other"
5960
- },
5961
- {
5962
- name:"SIGCHLD",
5963
- number:17,
5964
- action:"ignore",
5965
- description:"Child process terminated, paused or unpaused",
5966
- standard:"posix"
5967
- },
5968
- {
5969
- name:"SIGCLD",
5970
- number:17,
5971
- action:"ignore",
5972
- description:"Child process terminated, paused or unpaused",
5973
- standard:"other"
5974
- },
5975
- {
5976
- name:"SIGCONT",
5977
- number:18,
5978
- action:"unpause",
5979
- description:"Unpaused",
5980
- standard:"posix",
5981
- forced:true
5982
- },
5983
- {
5984
- name:"SIGSTOP",
5985
- number:19,
5986
- action:"pause",
5987
- description:"Paused",
5988
- standard:"posix",
5989
- forced:true
5990
- },
5991
- {
5992
- name:"SIGTSTP",
5993
- number:20,
5994
- action:"pause",
5995
- description:"Paused using CTRL-Z or \"suspend\"",
5996
- standard:"posix"
5997
- },
5998
- {
5999
- name:"SIGTTIN",
6000
- number:21,
6001
- action:"pause",
6002
- description:"Background process cannot read terminal input",
6003
- standard:"posix"
6004
- },
6005
- {
6006
- name:"SIGBREAK",
6007
- number:21,
6008
- action:"terminate",
6009
- description:"User interruption with CTRL-BREAK",
6010
- standard:"other"
6011
- },
6012
- {
6013
- name:"SIGTTOU",
6014
- number:22,
6015
- action:"pause",
6016
- description:"Background process cannot write to terminal output",
6017
- standard:"posix"
6018
- },
6019
- {
6020
- name:"SIGURG",
6021
- number:23,
6022
- action:"ignore",
6023
- description:"Socket received out-of-band data",
6024
- standard:"bsd"
6025
- },
6026
- {
6027
- name:"SIGXCPU",
6028
- number:24,
6029
- action:"core",
6030
- description:"Process timed out",
6031
- standard:"bsd"
6032
- },
6033
- {
6034
- name:"SIGXFSZ",
6035
- number:25,
6036
- action:"core",
6037
- description:"File too big",
6038
- standard:"bsd"
6039
- },
6040
- {
6041
- name:"SIGVTALRM",
6042
- number:26,
6043
- action:"terminate",
6044
- description:"Timeout or timer",
6045
- standard:"bsd"
6046
- },
6047
- {
6048
- name:"SIGPROF",
6049
- number:27,
6050
- action:"terminate",
6051
- description:"Timeout or timer",
6052
- standard:"bsd"
6053
- },
6054
- {
6055
- name:"SIGWINCH",
6056
- number:28,
6057
- action:"ignore",
6058
- description:"Terminal window size changed",
6059
- standard:"bsd"
6060
- },
6061
- {
6062
- name:"SIGIO",
6063
- number:29,
6064
- action:"terminate",
6065
- description:"I/O is available",
6066
- standard:"other"
6067
- },
6068
- {
6069
- name:"SIGPOLL",
6070
- number:29,
6071
- action:"terminate",
6072
- description:"Watched event",
6073
- standard:"other"
6074
- },
6075
- {
6076
- name:"SIGINFO",
6077
- number:29,
6078
- action:"ignore",
6079
- description:"Request for process information",
6080
- standard:"other"
6081
- },
6082
- {
6083
- name:"SIGPWR",
6084
- number:30,
6085
- action:"terminate",
6086
- description:"Device running out of power",
6087
- standard:"systemv"
6088
- },
6089
- {
6090
- name:"SIGSYS",
6091
- number:31,
6092
- action:"core",
6093
- description:"Invalid system call",
6094
- standard:"other"
6095
- },
6096
- {
6097
- name:"SIGUNUSED",
6098
- number:31,
6099
- action:"terminate",
6100
- description:"Invalid system call",
6101
- standard:"other"
6102
- }];
6103
-
6104
- const getSignals=()=>{
6105
- const realtimeSignals=getRealtimeSignals();
6106
- const signals=[...SIGNALS,...realtimeSignals].map(normalizeSignal);
6107
- return signals
6108
- };
6109
-
6110
-
6111
-
6112
-
6113
-
6114
-
6115
-
6116
- const normalizeSignal=({
6117
- name,
6118
- number:defaultNumber,
6119
- description,
6120
- action,
6121
- forced=false,
6122
- standard
6123
- })=>{
6124
- const{
6125
- signals:{[name]:constantSignal}
6126
- }=node_os.constants;
6127
- const supported=constantSignal!==undefined;
6128
- const number=supported?constantSignal:defaultNumber;
6129
- return {name,number,description,supported,action,forced,standard}
6130
- };
6131
-
6132
- const getSignalsByName=()=>{
6133
- const signals=getSignals();
6134
- return Object.fromEntries(signals.map(getSignalByName))
6135
- };
6136
-
6137
- const getSignalByName=({
6138
- name,
6139
- number,
6140
- description,
6141
- supported,
6142
- action,
6143
- forced,
6144
- standard
6145
- })=>[name,{name,number,description,supported,action,forced,standard}];
6146
-
6147
- const signalsByName=getSignalsByName();
6148
-
6149
-
6150
-
6151
-
6152
- const getSignalsByNumber=()=>{
6153
- const signals=getSignals();
6154
- const length=SIGRTMAX+1;
6155
- const signalsA=Array.from({length},(value,number)=>
6156
- getSignalByNumber(number,signals)
6157
- );
6158
- return Object.assign({},...signalsA)
6159
- };
6160
-
6161
- const getSignalByNumber=(number,signals)=>{
6162
- const signal=findSignalByNumber(number,signals);
6163
-
6164
- if(signal===undefined){
6165
- return {}
6166
- }
6167
-
6168
- const{name,description,supported,action,forced,standard}=signal;
6169
- return {
6170
- [number]:{
6171
- name,
6172
- number,
6173
- description,
6174
- supported,
6175
- action,
6176
- forced,
6177
- standard
6178
- }
6179
- }
6180
- };
6181
-
6182
-
6183
-
6184
- const findSignalByNumber=(number,signals)=>{
6185
- const signal=signals.find(({name})=>node_os.constants.signals[name]===number);
6186
-
6187
- if(signal!==undefined){
6188
- return signal
6189
- }
6190
-
6191
- return signals.find((signalA)=>signalA.number===number)
6192
- };
6193
-
6194
- getSignalsByNumber();
6195
-
6196
7080
  function stripFinalNewline(input) {
6197
7081
  if (typeof input === 'string') {
6198
7082
  return stripFinalNewlineString(input);
@@ -6714,6 +7598,17 @@ const getMaxBufferUnit = (readableObjectMode, lines, encoding) => {
6714
7598
  return 'characters';
6715
7599
  };
6716
7600
 
7601
+ // Check the `maxBuffer` option with `result.ipcOutput`
7602
+ const checkIpcMaxBuffer = (subprocess, ipcOutput, maxBuffer) => {
7603
+ if (ipcOutput.length !== maxBuffer) {
7604
+ return;
7605
+ }
7606
+
7607
+ const error = new MaxBufferError();
7608
+ error.maxBufferInfo = {fdNumber: 'ipc'};
7609
+ throw error;
7610
+ };
7611
+
6717
7612
  // Error message when `maxBuffer` is hit
6718
7613
  const getMaxBufferMessage = (error, maxBuffer) => {
6719
7614
  const {streamName, threshold, unit} = getMaxBufferInfo(error, maxBuffer);
@@ -6727,6 +7622,11 @@ const getMaxBufferInfo = (error, maxBuffer) => {
6727
7622
 
6728
7623
  const {maxBufferInfo: {fdNumber, unit}} = error;
6729
7624
  delete error.maxBufferInfo;
7625
+
7626
+ if (fdNumber === 'ipc') {
7627
+ return {streamName: 'IPC output', threshold: maxBuffer.at(-1), unit: 'messages'};
7628
+ }
7629
+
6730
7630
  return {streamName: getStreamName(fdNumber), threshold: maxBuffer[fdNumber], unit};
6731
7631
  };
6732
7632
 
@@ -6754,6 +7654,7 @@ const getMaxBufferSync = ([, stdoutMaxBuffer]) => stdoutMaxBuffer;
6754
7654
  const createMessages = ({
6755
7655
  stdio,
6756
7656
  all,
7657
+ ipcOutput,
6757
7658
  originalError,
6758
7659
  signal,
6759
7660
  signalDescription,
@@ -6761,7 +7662,11 @@ const createMessages = ({
6761
7662
  escapedCommand,
6762
7663
  timedOut,
6763
7664
  isCanceled,
7665
+ isGracefullyCanceled,
6764
7666
  isMaxBuffer,
7667
+ isForcefullyTerminated,
7668
+ forceKillAfterDelay,
7669
+ killSignal,
6765
7670
  maxBuffer,
6766
7671
  timeout,
6767
7672
  cwd,
@@ -6778,33 +7683,73 @@ const createMessages = ({
6778
7683
  signalDescription,
6779
7684
  exitCode,
6780
7685
  isCanceled,
7686
+ isGracefullyCanceled,
7687
+ isForcefullyTerminated,
7688
+ forceKillAfterDelay,
7689
+ killSignal,
6781
7690
  });
6782
7691
  const originalMessage = getOriginalMessage(originalError, cwd);
6783
7692
  const suffix = originalMessage === undefined ? '' : `\n${originalMessage}`;
6784
7693
  const shortMessage = `${prefix}: ${escapedCommand}${suffix}`;
6785
7694
  const messageStdio = all === undefined ? [stdio[2], stdio[1]] : [all];
6786
- const message = [shortMessage, ...messageStdio, ...stdio.slice(3)]
7695
+ const message = [
7696
+ shortMessage,
7697
+ ...messageStdio,
7698
+ ...stdio.slice(3),
7699
+ ipcOutput.map(ipcMessage => serializeIpcMessage(ipcMessage)).join('\n'),
7700
+ ]
6787
7701
  .map(messagePart => escapeLines(stripFinalNewline(serializeMessagePart(messagePart))))
6788
7702
  .filter(Boolean)
6789
7703
  .join('\n\n');
6790
7704
  return {originalMessage, shortMessage, message};
6791
7705
  };
6792
7706
 
6793
- const getErrorPrefix = ({originalError, timedOut, timeout, isMaxBuffer, maxBuffer, errorCode, signal, signalDescription, exitCode, isCanceled}) => {
7707
+ const getErrorPrefix = ({
7708
+ originalError,
7709
+ timedOut,
7710
+ timeout,
7711
+ isMaxBuffer,
7712
+ maxBuffer,
7713
+ errorCode,
7714
+ signal,
7715
+ signalDescription,
7716
+ exitCode,
7717
+ isCanceled,
7718
+ isGracefullyCanceled,
7719
+ isForcefullyTerminated,
7720
+ forceKillAfterDelay,
7721
+ killSignal,
7722
+ }) => {
7723
+ const forcefulSuffix = getForcefulSuffix(isForcefullyTerminated, forceKillAfterDelay);
7724
+
6794
7725
  if (timedOut) {
6795
- return `Command timed out after ${timeout} milliseconds`;
7726
+ return `Command timed out after ${timeout} milliseconds${forcefulSuffix}`;
7727
+ }
7728
+
7729
+ if (isGracefullyCanceled) {
7730
+ if (signal === undefined) {
7731
+ return `Command was gracefully canceled with exit code ${exitCode}`;
7732
+ }
7733
+
7734
+ return isForcefullyTerminated
7735
+ ? `Command was gracefully canceled${forcefulSuffix}`
7736
+ : `Command was gracefully canceled with ${signal} (${signalDescription})`;
6796
7737
  }
6797
7738
 
6798
7739
  if (isCanceled) {
6799
- return 'Command was canceled';
7740
+ return `Command was canceled${forcefulSuffix}`;
6800
7741
  }
6801
7742
 
6802
7743
  if (isMaxBuffer) {
6803
- return getMaxBufferMessage(originalError, maxBuffer);
7744
+ return `${getMaxBufferMessage(originalError, maxBuffer)}${forcefulSuffix}`;
6804
7745
  }
6805
7746
 
6806
7747
  if (errorCode !== undefined) {
6807
- return `Command failed with ${errorCode}`;
7748
+ return `Command failed with ${errorCode}${forcefulSuffix}`;
7749
+ }
7750
+
7751
+ if (isForcefullyTerminated) {
7752
+ return `Command was killed with ${killSignal} (${getSignalDescription(killSignal)})${forcefulSuffix}`;
6808
7753
  }
6809
7754
 
6810
7755
  if (signal !== undefined) {
@@ -6818,6 +7763,10 @@ const getErrorPrefix = ({originalError, timedOut, timeout, isMaxBuffer, maxBuffe
6818
7763
  return 'Command failed';
6819
7764
  };
6820
7765
 
7766
+ const getForcefulSuffix = (isForcefullyTerminated, forceKillAfterDelay) => isForcefullyTerminated
7767
+ ? ` and was forcefully terminated after ${forceKillAfterDelay} milliseconds`
7768
+ : '';
7769
+
6821
7770
  const getOriginalMessage = (originalError, cwd) => {
6822
7771
  if (originalError instanceof DiscardedError) {
6823
7772
  return;
@@ -6830,6 +7779,10 @@ const getOriginalMessage = (originalError, cwd) => {
6830
7779
  return escapedOriginalMessage === '' ? undefined : escapedOriginalMessage;
6831
7780
  };
6832
7781
 
7782
+ const serializeIpcMessage = ipcMessage => typeof ipcMessage === 'string'
7783
+ ? ipcMessage
7784
+ : node_util.inspect(ipcMessage);
7785
+
6833
7786
  const serializeMessagePart = messagePart => Array.isArray(messagePart)
6834
7787
  ? messagePart.map(messageItem => stripFinalNewline(serializeMessageItem(messageItem))).filter(Boolean).join('\n')
6835
7788
  : serializeMessageItem(messagePart);
@@ -6852,6 +7805,7 @@ const makeSuccessResult = ({
6852
7805
  escapedCommand,
6853
7806
  stdio,
6854
7807
  all,
7808
+ ipcOutput,
6855
7809
  options: {cwd},
6856
7810
  startTime,
6857
7811
  }) => omitUndefinedProperties({
@@ -6862,13 +7816,16 @@ const makeSuccessResult = ({
6862
7816
  failed: false,
6863
7817
  timedOut: false,
6864
7818
  isCanceled: false,
7819
+ isGracefullyCanceled: false,
6865
7820
  isTerminated: false,
6866
7821
  isMaxBuffer: false,
7822
+ isForcefullyTerminated: false,
6867
7823
  exitCode: 0,
6868
7824
  stdout: stdio[1],
6869
7825
  stderr: stdio[2],
6870
7826
  all,
6871
7827
  stdio,
7828
+ ipcOutput,
6872
7829
  pipedFrom: [],
6873
7830
  });
6874
7831
 
@@ -6888,8 +7845,11 @@ const makeEarlyError = ({
6888
7845
  startTime,
6889
7846
  timedOut: false,
6890
7847
  isCanceled: false,
7848
+ isGracefullyCanceled: false,
6891
7849
  isMaxBuffer: false,
7850
+ isForcefullyTerminated: false,
6892
7851
  stdio: Array.from({length: fileDescriptors.length}),
7852
+ ipcOutput: [],
6893
7853
  options,
6894
7854
  isSync,
6895
7855
  });
@@ -6902,18 +7862,29 @@ const makeError = ({
6902
7862
  startTime,
6903
7863
  timedOut,
6904
7864
  isCanceled,
7865
+ isGracefullyCanceled,
6905
7866
  isMaxBuffer,
7867
+ isForcefullyTerminated,
6906
7868
  exitCode: rawExitCode,
6907
7869
  signal: rawSignal,
6908
7870
  stdio,
6909
7871
  all,
6910
- options: {timeoutDuration, timeout = timeoutDuration, cwd, maxBuffer},
7872
+ ipcOutput,
7873
+ options: {
7874
+ timeoutDuration,
7875
+ timeout = timeoutDuration,
7876
+ forceKillAfterDelay,
7877
+ killSignal,
7878
+ cwd,
7879
+ maxBuffer,
7880
+ },
6911
7881
  isSync,
6912
7882
  }) => {
6913
7883
  const {exitCode, signal, signalDescription} = normalizeExitPayload(rawExitCode, rawSignal);
6914
7884
  const {originalMessage, shortMessage, message} = createMessages({
6915
7885
  stdio,
6916
7886
  all,
7887
+ ipcOutput,
6917
7888
  originalError,
6918
7889
  signal,
6919
7890
  signalDescription,
@@ -6921,7 +7892,11 @@ const makeError = ({
6921
7892
  escapedCommand,
6922
7893
  timedOut,
6923
7894
  isCanceled,
7895
+ isGracefullyCanceled,
6924
7896
  isMaxBuffer,
7897
+ isForcefullyTerminated,
7898
+ forceKillAfterDelay,
7899
+ killSignal,
6925
7900
  maxBuffer,
6926
7901
  timeout,
6927
7902
  cwd,
@@ -6934,12 +7909,15 @@ const makeError = ({
6934
7909
  startTime,
6935
7910
  timedOut,
6936
7911
  isCanceled,
7912
+ isGracefullyCanceled,
6937
7913
  isMaxBuffer,
7914
+ isForcefullyTerminated,
6938
7915
  exitCode,
6939
7916
  signal,
6940
7917
  signalDescription,
6941
7918
  stdio,
6942
7919
  all,
7920
+ ipcOutput,
6943
7921
  cwd,
6944
7922
  originalMessage,
6945
7923
  shortMessage,
@@ -6954,12 +7932,15 @@ const getErrorProperties = ({
6954
7932
  startTime,
6955
7933
  timedOut,
6956
7934
  isCanceled,
7935
+ isGracefullyCanceled,
6957
7936
  isMaxBuffer,
7937
+ isForcefullyTerminated,
6958
7938
  exitCode,
6959
7939
  signal,
6960
7940
  signalDescription,
6961
7941
  stdio,
6962
7942
  all,
7943
+ ipcOutput,
6963
7944
  cwd,
6964
7945
  originalMessage,
6965
7946
  shortMessage,
@@ -6973,8 +7954,10 @@ const getErrorProperties = ({
6973
7954
  failed: true,
6974
7955
  timedOut,
6975
7956
  isCanceled,
7957
+ isGracefullyCanceled,
6976
7958
  isTerminated: signal !== undefined,
6977
7959
  isMaxBuffer,
7960
+ isForcefullyTerminated,
6978
7961
  exitCode,
6979
7962
  signal,
6980
7963
  signalDescription,
@@ -6983,6 +7966,7 @@ const getErrorProperties = ({
6983
7966
  stderr: stdio[2],
6984
7967
  all,
6985
7968
  stdio,
7969
+ ipcOutput,
6986
7970
  pipedFrom: [],
6987
7971
  });
6988
7972
 
@@ -6993,7 +7977,7 @@ const omitUndefinedProperties = result => Object.fromEntries(Object.entries(resu
6993
7977
  const normalizeExitPayload = (rawExitCode, rawSignal) => {
6994
7978
  const exitCode = rawExitCode === null ? undefined : rawExitCode;
6995
7979
  const signal = rawSignal === null ? undefined : rawSignal;
6996
- const signalDescription = signal === undefined ? undefined : signalsByName[rawSignal].description;
7980
+ const signalDescription = signal === undefined ? undefined : getSignalDescription(rawSignal);
6997
7981
  return {exitCode, signal, signalDescription};
6998
7982
  };
6999
7983
 
@@ -7633,11 +8617,18 @@ const getStandardStreamDirection = value => {
7633
8617
  // When the ambiguity remains, we default to `output` since it is the most common use case for additional file descriptors.
7634
8618
  const DEFAULT_DIRECTION = 'output';
7635
8619
 
8620
+ // The `ipc` option adds an `ipc` item to the `stdio` option
8621
+ const normalizeIpcStdioArray = (stdioArray, ipc) => ipc && !stdioArray.includes('ipc')
8622
+ ? [...stdioArray, 'ipc']
8623
+ : stdioArray;
8624
+
7636
8625
  // Add support for `stdin`/`stdout`/`stderr` as an alias for `stdio`.
7637
8626
  // Also normalize the `stdio` option.
7638
8627
  const normalizeStdioOption = ({stdio, ipc, buffer, verbose, ...options}, isSync) => {
7639
8628
  const stdioArray = getStdioArray(stdio, options).map((stdioOption, fdNumber) => addDefaultValue(stdioOption, fdNumber));
7640
- return isSync ? normalizeStdioSync(stdioArray, buffer, verbose) : normalizeStdioAsync(stdioArray, ipc);
8629
+ return isSync
8630
+ ? normalizeStdioSync(stdioArray, buffer, verbose)
8631
+ : normalizeIpcStdioArray(stdioArray, ipc);
7641
8632
  };
7642
8633
 
7643
8634
  const getStdioArray = (stdio, options) => {
@@ -7688,118 +8679,6 @@ const normalizeStdioSync = (stdioArray, buffer, verbose) => stdioArray.map((stdi
7688
8679
  const isOutputPipeOnly = stdioOption => stdioOption === 'pipe'
7689
8680
  || (Array.isArray(stdioOption) && stdioOption.every(item => item === 'pipe'));
7690
8681
 
7691
- // The `ipc` option adds an `ipc` item to the `stdio` option
7692
- const normalizeStdioAsync = (stdioArray, ipc) => ipc && !stdioArray.includes('ipc')
7693
- ? [...stdioArray, 'ipc']
7694
- : stdioArray;
7695
-
7696
- // Retrieve stream targeted by the `to` option
7697
- const getToStream = (destination, to = 'stdin') => {
7698
- const isWritable = true;
7699
- const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(destination);
7700
- const fdNumber = getFdNumber(fileDescriptors, to, isWritable);
7701
- const destinationStream = destination.stdio[fdNumber];
7702
-
7703
- if (destinationStream === null) {
7704
- throw new TypeError(getInvalidStdioOptionMessage(fdNumber, to, options, isWritable));
7705
- }
7706
-
7707
- return destinationStream;
7708
- };
7709
-
7710
- // Retrieve stream targeted by the `from` option
7711
- const getFromStream = (source, from = 'stdout') => {
7712
- const isWritable = false;
7713
- const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(source);
7714
- const fdNumber = getFdNumber(fileDescriptors, from, isWritable);
7715
- const sourceStream = fdNumber === 'all' ? source.all : source.stdio[fdNumber];
7716
-
7717
- if (sourceStream === null || sourceStream === undefined) {
7718
- throw new TypeError(getInvalidStdioOptionMessage(fdNumber, from, options, isWritable));
7719
- }
7720
-
7721
- return sourceStream;
7722
- };
7723
-
7724
- // Keeps track of the options passed to each Execa call
7725
- const SUBPROCESS_OPTIONS = new WeakMap();
7726
-
7727
- const getFdNumber = (fileDescriptors, fdName, isWritable) => {
7728
- const fdNumber = parseFdNumber(fdName, isWritable);
7729
- validateFdNumber(fdNumber, fdName, isWritable, fileDescriptors);
7730
- return fdNumber;
7731
- };
7732
-
7733
- const parseFdNumber = (fdName, isWritable) => {
7734
- const fdNumber = parseFd(fdName);
7735
- if (fdNumber !== undefined) {
7736
- return fdNumber;
7737
- }
7738
-
7739
- const {validOptions, defaultValue} = isWritable
7740
- ? {validOptions: '"stdin"', defaultValue: 'stdin'}
7741
- : {validOptions: '"stdout", "stderr", "all"', defaultValue: 'stdout'};
7742
- throw new TypeError(`"${getOptionName(isWritable)}" must not be "${fdName}".
7743
- It must be ${validOptions} or "fd3", "fd4" (and so on).
7744
- It is optional and defaults to "${defaultValue}".`);
7745
- };
7746
-
7747
- const validateFdNumber = (fdNumber, fdName, isWritable, fileDescriptors) => {
7748
- const fileDescriptor = fileDescriptors[getUsedDescriptor(fdNumber)];
7749
- if (fileDescriptor === undefined) {
7750
- throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. That file descriptor does not exist.
7751
- Please set the "stdio" option to ensure that file descriptor exists.`);
7752
- }
7753
-
7754
- if (fileDescriptor.direction === 'input' && !isWritable) {
7755
- throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a readable stream, not writable.`);
7756
- }
7757
-
7758
- if (fileDescriptor.direction !== 'input' && isWritable) {
7759
- throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a writable stream, not readable.`);
7760
- }
7761
- };
7762
-
7763
- const getInvalidStdioOptionMessage = (fdNumber, fdName, options, isWritable) => {
7764
- if (fdNumber === 'all' && !options.all) {
7765
- return 'The "all" option must be true to use "from: \'all\'".';
7766
- }
7767
-
7768
- const {optionName, optionValue} = getInvalidStdioOption(fdNumber, options);
7769
- return `The "${optionName}: ${serializeOptionValue(optionValue)}" option is incompatible with using "${getOptionName(isWritable)}: ${serializeOptionValue(fdName)}".
7770
- Please set this option with "pipe" instead.`;
7771
- };
7772
-
7773
- const getInvalidStdioOption = (fdNumber, {stdin, stdout, stderr, stdio}) => {
7774
- const usedDescriptor = getUsedDescriptor(fdNumber);
7775
-
7776
- if (usedDescriptor === 0 && stdin !== undefined) {
7777
- return {optionName: 'stdin', optionValue: stdin};
7778
- }
7779
-
7780
- if (usedDescriptor === 1 && stdout !== undefined) {
7781
- return {optionName: 'stdout', optionValue: stdout};
7782
- }
7783
-
7784
- if (usedDescriptor === 2 && stderr !== undefined) {
7785
- return {optionName: 'stderr', optionValue: stderr};
7786
- }
7787
-
7788
- return {optionName: `stdio[${usedDescriptor}]`, optionValue: stdio[usedDescriptor]};
7789
- };
7790
-
7791
- const getUsedDescriptor = fdNumber => fdNumber === 'all' ? 1 : fdNumber;
7792
-
7793
- const getOptionName = isWritable => isWritable ? 'to' : 'from';
7794
-
7795
- const serializeOptionValue = value => {
7796
- if (typeof value === 'string') {
7797
- return `'${value}'`;
7798
- }
7799
-
7800
- return typeof value === 'number' ? `${value}` : 'Stream';
7801
- };
7802
-
7803
8682
  // When we use multiple `stdio` values for the same streams, we pass 'pipe' to `child_process.spawn()`.
7804
8683
  // We then emulate the piping done by core Node.js.
7805
8684
  // To do so, we transform the following values:
@@ -8032,7 +8911,7 @@ const getDuplicateStreamInstance = ({otherStdioItems, type, value, optionName, d
8032
8911
 
8033
8912
  const hasSameValue = ({type, value}, secondValue) => {
8034
8913
  if (type === 'filePath') {
8035
- return value.path === secondValue.path;
8914
+ return value.file === secondValue.file;
8036
8915
  }
8037
8916
 
8038
8917
  if (type === 'fileUrl') {
@@ -8782,7 +9661,7 @@ const fdUsesVerbose = fdNumber => fdNumber === 1 || fdNumber === 2;
8782
9661
 
8783
9662
  const PIPED_STDIO_VALUES = new Set(['pipe', 'overlapped']);
8784
9663
 
8785
- // `verbose` printing logic with async methods
9664
+ // `verbose: 'full'` printing logic with async methods
8786
9665
  const logLines = async (linesIterable, stream, verboseInfo) => {
8787
9666
  for await (const line of linesIterable) {
8788
9667
  if (!isPipingStream(stream)) {
@@ -8791,7 +9670,7 @@ const logLines = async (linesIterable, stream, verboseInfo) => {
8791
9670
  }
8792
9671
  };
8793
9672
 
8794
- // `verbose` printing logic with sync methods
9673
+ // `verbose: 'full'` printing logic with sync methods
8795
9674
  const logLinesSync = (linesArray, verboseInfo) => {
8796
9675
  for (const line of linesArray) {
8797
9676
  logLine(line, verboseInfo);
@@ -8809,15 +9688,9 @@ const isPipingStream = stream => stream._readableState.pipes.length > 0;
8809
9688
 
8810
9689
  // When `verbose` is `full`, print stdout|stderr
8811
9690
  const logLine = (line, {verboseId}) => {
8812
- const lines = typeof line === 'string' ? line : node_util.inspect(line);
8813
- const escapedLines = escapeLines(lines);
8814
- const spacedLines = escapedLines.replaceAll('\t', ' '.repeat(TAB_SIZE));
8815
- verboseLog(spacedLines, verboseId, 'output');
9691
+ verboseLog(serializeLogMessage(line), verboseId, 'output');
8816
9692
  };
8817
9693
 
8818
- // Same as `util.inspect()`
8819
- const TAB_SIZE = 2;
8820
-
8821
9694
  // Apply `stdout`/`stderr` options, after spawning, in sync mode
8822
9695
  const transformOutputSync = ({fileDescriptors, syncResult: {output}, options, isMaxBuffer, verboseInfo}) => {
8823
9696
  if (output === null) {
@@ -8959,13 +9832,19 @@ const getAllSync = ([, stdout, stderr], options) => {
8959
9832
  };
8960
9833
 
8961
9834
  // If `error` is emitted before `spawn`, `exit` will never be emitted.
8962
- // However, `error` might be emitted after `spawn`, e.g. with the `cancelSignal` option.
9835
+ // However, `error` might be emitted after `spawn`.
8963
9836
  // In that case, `exit` will still be emitted.
8964
9837
  // Since the `exit` event contains the signal name, we want to make sure we are listening for it.
8965
9838
  // This function also takes into account the following unlikely cases:
8966
9839
  // - `exit` being emitted in the same microtask as `spawn`
8967
9840
  // - `error` being emitted multiple times
8968
- const waitForExit = async subprocess => {
9841
+ const waitForExit = async (subprocess, context) => {
9842
+ const [exitCode, signal] = await waitForExitOrError(subprocess);
9843
+ context.isForcefullyTerminated ??= false;
9844
+ return [exitCode, signal];
9845
+ };
9846
+
9847
+ const waitForExitOrError = async subprocess => {
8969
9848
  const [spawnPayload, exitPayload] = await Promise.allSettled([
8970
9849
  require$$0.once(subprocess, 'spawn'),
8971
9850
  require$$0.once(subprocess, 'exit'),
@@ -9026,7 +9905,7 @@ const getResultError = (error, exitCode, signal) => {
9026
9905
  return isFailedExit(exitCode, signal) ? new DiscardedError() : undefined;
9027
9906
  };
9028
9907
 
9029
- // Main shared logic for all sync methods: `execaSync()`, `execaCommandSync()`, `$.sync()`
9908
+ // Main shared logic for all sync methods: `execaSync()`, `$.sync()`
9030
9909
  const execaCoreSync = (rawFile, rawArguments, rawOptions) => {
9031
9910
  const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleSyncArguments(rawFile, rawArguments, rawOptions);
9032
9911
  const result = spawnSubprocessSync({
@@ -9071,7 +9950,11 @@ const handleSyncArguments = (rawFile, rawArguments, rawOptions) => {
9071
9950
  const normalizeSyncOptions = options => options.node && !options.ipc ? {...options, ipc: false} : options;
9072
9951
 
9073
9952
  // Options validation logic specific to sync methods
9074
- const validateSyncOptions = ({ipc, detached, cancelSignal}) => {
9953
+ const validateSyncOptions = ({ipc, ipcInput, detached, cancelSignal}) => {
9954
+ if (ipcInput) {
9955
+ throwInvalidSyncOption('ipcInput');
9956
+ }
9957
+
9075
9958
  if (ipc) {
9076
9959
  throwInvalidSyncOption('ipc: true');
9077
9960
  }
@@ -9155,6 +10038,7 @@ const getSyncResult = ({error, exitCode, signal, timedOut, isMaxBuffer, stdio, a
9155
10038
  escapedCommand,
9156
10039
  stdio,
9157
10040
  all,
10041
+ ipcOutput: [],
9158
10042
  options,
9159
10043
  startTime,
9160
10044
  })
@@ -9164,16 +10048,208 @@ const getSyncResult = ({error, exitCode, signal, timedOut, isMaxBuffer, stdio, a
9164
10048
  escapedCommand,
9165
10049
  timedOut,
9166
10050
  isCanceled: false,
10051
+ isGracefullyCanceled: false,
9167
10052
  isMaxBuffer,
10053
+ isForcefullyTerminated: false,
9168
10054
  exitCode,
9169
10055
  signal,
9170
10056
  stdio,
9171
10057
  all,
10058
+ ipcOutput: [],
9172
10059
  options,
9173
10060
  startTime,
9174
10061
  isSync: true,
9175
10062
  });
9176
10063
 
10064
+ // Like `[sub]process.once('message')` but promise-based
10065
+ const getOneMessage = ({anyProcess, channel, isSubprocess, ipc}, {reference = true, filter} = {}) => {
10066
+ validateIpcMethod({
10067
+ methodName: 'getOneMessage',
10068
+ isSubprocess,
10069
+ ipc,
10070
+ isConnected: isConnected(anyProcess),
10071
+ });
10072
+
10073
+ return getOneMessageAsync({
10074
+ anyProcess,
10075
+ channel,
10076
+ isSubprocess,
10077
+ filter,
10078
+ reference,
10079
+ });
10080
+ };
10081
+
10082
+ const getOneMessageAsync = async ({anyProcess, channel, isSubprocess, filter, reference}) => {
10083
+ addReference(channel, reference);
10084
+ const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
10085
+ const controller = new AbortController();
10086
+ try {
10087
+ return await Promise.race([
10088
+ getMessage(ipcEmitter, filter, controller),
10089
+ throwOnDisconnect(ipcEmitter, isSubprocess, controller),
10090
+ throwOnStrictError(ipcEmitter, isSubprocess, controller),
10091
+ ]);
10092
+ } catch (error) {
10093
+ disconnect(anyProcess);
10094
+ throw error;
10095
+ } finally {
10096
+ controller.abort();
10097
+ removeReference(channel, reference);
10098
+ }
10099
+ };
10100
+
10101
+ const getMessage = async (ipcEmitter, filter, {signal}) => {
10102
+ if (filter === undefined) {
10103
+ const [message] = await require$$0.once(ipcEmitter, 'message', {signal});
10104
+ return message;
10105
+ }
10106
+
10107
+ for await (const [message] of require$$0.on(ipcEmitter, 'message', {signal})) {
10108
+ if (filter(message)) {
10109
+ return message;
10110
+ }
10111
+ }
10112
+ };
10113
+
10114
+ const throwOnDisconnect = async (ipcEmitter, isSubprocess, {signal}) => {
10115
+ await require$$0.once(ipcEmitter, 'disconnect', {signal});
10116
+ throwOnEarlyDisconnect(isSubprocess);
10117
+ };
10118
+
10119
+ const throwOnStrictError = async (ipcEmitter, isSubprocess, {signal}) => {
10120
+ const [error] = await require$$0.once(ipcEmitter, 'strict:error', {signal});
10121
+ throw getStrictResponseError(error, isSubprocess);
10122
+ };
10123
+
10124
+ // Like `[sub]process.on('message')` but promise-based
10125
+ const getEachMessage = ({anyProcess, channel, isSubprocess, ipc}, {reference = true} = {}) => loopOnMessages({
10126
+ anyProcess,
10127
+ channel,
10128
+ isSubprocess,
10129
+ ipc,
10130
+ shouldAwait: !isSubprocess,
10131
+ reference,
10132
+ });
10133
+
10134
+ // Same but used internally
10135
+ const loopOnMessages = ({anyProcess, channel, isSubprocess, ipc, shouldAwait, reference}) => {
10136
+ validateIpcMethod({
10137
+ methodName: 'getEachMessage',
10138
+ isSubprocess,
10139
+ ipc,
10140
+ isConnected: isConnected(anyProcess),
10141
+ });
10142
+
10143
+ addReference(channel, reference);
10144
+ const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
10145
+ const controller = new AbortController();
10146
+ const state = {};
10147
+ stopOnDisconnect(anyProcess, ipcEmitter, controller);
10148
+ abortOnStrictError({
10149
+ ipcEmitter,
10150
+ isSubprocess,
10151
+ controller,
10152
+ state,
10153
+ });
10154
+ return iterateOnMessages({
10155
+ anyProcess,
10156
+ channel,
10157
+ ipcEmitter,
10158
+ isSubprocess,
10159
+ shouldAwait,
10160
+ controller,
10161
+ state,
10162
+ reference,
10163
+ });
10164
+ };
10165
+
10166
+ const stopOnDisconnect = async (anyProcess, ipcEmitter, controller) => {
10167
+ try {
10168
+ await require$$0.once(ipcEmitter, 'disconnect', {signal: controller.signal});
10169
+ controller.abort();
10170
+ } catch {}
10171
+ };
10172
+
10173
+ const abortOnStrictError = async ({ipcEmitter, isSubprocess, controller, state}) => {
10174
+ try {
10175
+ const [error] = await require$$0.once(ipcEmitter, 'strict:error', {signal: controller.signal});
10176
+ state.error = getStrictResponseError(error, isSubprocess);
10177
+ controller.abort();
10178
+ } catch {}
10179
+ };
10180
+
10181
+ const iterateOnMessages = async function * ({anyProcess, channel, ipcEmitter, isSubprocess, shouldAwait, controller, state, reference}) {
10182
+ try {
10183
+ for await (const [message] of require$$0.on(ipcEmitter, 'message', {signal: controller.signal})) {
10184
+ throwIfStrictError(state);
10185
+ yield message;
10186
+ }
10187
+ } catch {
10188
+ throwIfStrictError(state);
10189
+ } finally {
10190
+ controller.abort();
10191
+ removeReference(channel, reference);
10192
+
10193
+ if (!isSubprocess) {
10194
+ disconnect(anyProcess);
10195
+ }
10196
+
10197
+ if (shouldAwait) {
10198
+ await anyProcess;
10199
+ }
10200
+ }
10201
+ };
10202
+
10203
+ const throwIfStrictError = ({error}) => {
10204
+ if (error) {
10205
+ throw error;
10206
+ }
10207
+ };
10208
+
10209
+ // Add promise-based IPC methods in current process
10210
+ const addIpcMethods = (subprocess, {ipc}) => {
10211
+ Object.assign(subprocess, getIpcMethods(subprocess, false, ipc));
10212
+ };
10213
+
10214
+ // Get promise-based IPC in the subprocess
10215
+ const getIpcExport = () => {
10216
+ const anyProcess = process$3;
10217
+ const isSubprocess = true;
10218
+ const ipc = process$3.channel !== undefined;
10219
+
10220
+ return {
10221
+ ...getIpcMethods(anyProcess, isSubprocess, ipc),
10222
+ getCancelSignal: getCancelSignal.bind(undefined, {
10223
+ anyProcess,
10224
+ channel: anyProcess.channel,
10225
+ isSubprocess,
10226
+ ipc,
10227
+ }),
10228
+ };
10229
+ };
10230
+
10231
+ // Retrieve the `ipc` shared by both the current process and the subprocess
10232
+ const getIpcMethods = (anyProcess, isSubprocess, ipc) => ({
10233
+ sendMessage: sendMessage.bind(undefined, {
10234
+ anyProcess,
10235
+ channel: anyProcess.channel,
10236
+ isSubprocess,
10237
+ ipc,
10238
+ }),
10239
+ getOneMessage: getOneMessage.bind(undefined, {
10240
+ anyProcess,
10241
+ channel: anyProcess.channel,
10242
+ isSubprocess,
10243
+ ipc,
10244
+ }),
10245
+ getEachMessage: getEachMessage.bind(undefined, {
10246
+ anyProcess,
10247
+ channel: anyProcess.channel,
10248
+ isSubprocess,
10249
+ ipc,
10250
+ }),
10251
+ });
10252
+
9177
10253
  // When the subprocess fails to spawn.
9178
10254
  // We ensure the returned error is always both a promise and a subprocess.
9179
10255
  const handleEarlyError = ({error, command, escapedCommand, fileDescriptors, options, startTime, verboseInfo}) => {
@@ -9532,19 +10608,6 @@ const PASSTHROUGH_LISTENERS_COUNT = 2;
9532
10608
  // - once due to `stream.pipe(passThroughStream)`
9533
10609
  const PASSTHROUGH_LISTENERS_PER_STREAM = 1;
9534
10610
 
9535
- // Temporarily increase the maximum number of listeners on an eventEmitter
9536
- const incrementMaxListeners = (eventEmitter, maxListenersIncrement, signal) => {
9537
- const maxListeners = eventEmitter.getMaxListeners();
9538
- if (maxListeners === 0 || maxListeners === Number.POSITIVE_INFINITY) {
9539
- return;
9540
- }
9541
-
9542
- eventEmitter.setMaxListeners(maxListeners + maxListenersIncrement);
9543
- require$$0.addAbortListener(signal, () => {
9544
- eventEmitter.setMaxListeners(eventEmitter.getMaxListeners() - maxListenersIncrement);
9545
- });
9546
- };
9547
-
9548
10611
  // Similar to `Stream.pipeline(source, destination)`, but does not destroy standard streams
9549
10612
  const pipeStreams = (source, destination) => {
9550
10613
  source.pipe(destination);
@@ -10671,10 +11734,72 @@ const getAllMixed = ({all, stdout, stderr}) => all
10671
11734
  && stderr
10672
11735
  && stdout.readableObjectMode !== stderr.readableObjectMode;
10673
11736
 
11737
+ // When `verbose` is `'full'`, print IPC messages from the subprocess
11738
+ const shouldLogIpc = ({verbose}) => verbose.at(-1) === 'full';
11739
+
11740
+ const logIpcOutput = (message, {verboseId}) => {
11741
+ verboseLog(serializeLogMessage(message), verboseId, 'ipc');
11742
+ };
11743
+
11744
+ // Iterate through IPC messages sent by the subprocess
11745
+ const waitForIpcOutput = async ({
11746
+ subprocess,
11747
+ buffer: bufferArray,
11748
+ maxBuffer: maxBufferArray,
11749
+ ipc,
11750
+ ipcOutput,
11751
+ verboseInfo,
11752
+ }) => {
11753
+ if (!ipc) {
11754
+ return ipcOutput;
11755
+ }
11756
+
11757
+ const isVerbose = shouldLogIpc(verboseInfo);
11758
+ const buffer = bufferArray.at(-1);
11759
+ const maxBuffer = maxBufferArray.at(-1);
11760
+
11761
+ for await (const message of loopOnMessages({
11762
+ anyProcess: subprocess,
11763
+ channel: subprocess.channel,
11764
+ isSubprocess: false,
11765
+ ipc,
11766
+ shouldAwait: false,
11767
+ reference: true,
11768
+ })) {
11769
+ if (buffer) {
11770
+ checkIpcMaxBuffer(subprocess, ipcOutput, maxBuffer);
11771
+ ipcOutput.push(message);
11772
+ }
11773
+
11774
+ if (isVerbose) {
11775
+ logIpcOutput(message, verboseInfo);
11776
+ }
11777
+ }
11778
+
11779
+ return ipcOutput;
11780
+ };
11781
+
11782
+ const getBufferedIpcOutput = async (ipcOutputPromise, ipcOutput) => {
11783
+ await Promise.allSettled([ipcOutputPromise]);
11784
+ return ipcOutput;
11785
+ };
11786
+
10674
11787
  // Retrieve result of subprocess: exit code, signal, error, streams (stdout/stderr/all)
10675
11788
  const waitForSubprocessResult = async ({
10676
11789
  subprocess,
10677
- options: {encoding, buffer, maxBuffer, lines, timeoutDuration: timeout, stripFinalNewline},
11790
+ options: {
11791
+ encoding,
11792
+ buffer,
11793
+ maxBuffer,
11794
+ lines,
11795
+ timeoutDuration: timeout,
11796
+ cancelSignal,
11797
+ gracefulCancel,
11798
+ forceKillAfterDelay,
11799
+ stripFinalNewline,
11800
+ ipc,
11801
+ ipcInput,
11802
+ },
10678
11803
  context,
10679
11804
  verboseInfo,
10680
11805
  fileDescriptors,
@@ -10682,7 +11807,7 @@ const waitForSubprocessResult = async ({
10682
11807
  onInternalError,
10683
11808
  controller,
10684
11809
  }) => {
10685
- const exitPromise = waitForExit(subprocess);
11810
+ const exitPromise = waitForExit(subprocess, context);
10686
11811
  const streamInfo = {
10687
11812
  originalStreams,
10688
11813
  fileDescriptors,
@@ -10711,6 +11836,15 @@ const waitForSubprocessResult = async ({
10711
11836
  verboseInfo,
10712
11837
  streamInfo,
10713
11838
  });
11839
+ const ipcOutput = [];
11840
+ const ipcOutputPromise = waitForIpcOutput({
11841
+ subprocess,
11842
+ buffer,
11843
+ maxBuffer,
11844
+ ipc,
11845
+ ipcOutput,
11846
+ verboseInfo,
11847
+ });
10714
11848
  const originalPromises = waitForOriginalStreams(originalStreams, subprocess, streamInfo);
10715
11849
  const customStreamsEndPromises = waitForCustomStreamsEnd(fileDescriptors, streamInfo);
10716
11850
 
@@ -10721,19 +11855,38 @@ const waitForSubprocessResult = async ({
10721
11855
  waitForSuccessfulExit(exitPromise),
10722
11856
  Promise.all(stdioPromises),
10723
11857
  allPromise,
11858
+ ipcOutputPromise,
11859
+ sendIpcInput(subprocess, ipcInput),
10724
11860
  ...originalPromises,
10725
11861
  ...customStreamsEndPromises,
10726
11862
  ]),
10727
11863
  onInternalError,
10728
11864
  throwOnSubprocessError(subprocess, controller),
10729
11865
  ...throwOnTimeout(subprocess, timeout, context, controller),
11866
+ ...throwOnCancel({
11867
+ subprocess,
11868
+ cancelSignal,
11869
+ gracefulCancel,
11870
+ context,
11871
+ controller,
11872
+ }),
11873
+ ...throwOnGracefulCancel({
11874
+ subprocess,
11875
+ cancelSignal,
11876
+ gracefulCancel,
11877
+ forceKillAfterDelay,
11878
+ context,
11879
+ controller,
11880
+ }),
10730
11881
  ]);
10731
11882
  } catch (error) {
11883
+ context.terminationReason ??= 'other';
10732
11884
  return Promise.all([
10733
11885
  {error},
10734
11886
  exitPromise,
10735
11887
  Promise.all(stdioPromises.map(stdioPromise => getBufferedData(stdioPromise))),
10736
11888
  getBufferedData(allPromise),
11889
+ getBufferedIpcOutput(ipcOutputPromise, ipcOutput),
10737
11890
  Promise.allSettled(originalPromises),
10738
11891
  Promise.allSettled(customStreamsEndPromises),
10739
11892
  ]);
@@ -10763,14 +11916,6 @@ const throwOnSubprocessError = async (subprocess, {signal}) => {
10763
11916
  throw error;
10764
11917
  };
10765
11918
 
10766
- const createDeferred = () => {
10767
- const methods = {};
10768
- const promise = new Promise((resolve, reject) => {
10769
- Object.assign(methods, {resolve, reject});
10770
- });
10771
- return Object.assign(promise, methods);
10772
- };
10773
-
10774
11919
  // When using multiple `.readable()`/`.writable()`/`.duplex()`, `final` and `destroy` should wait for other streams
10775
11920
  const initializeConcurrentStreams = () => ({
10776
11921
  readableDestroy: new WeakMap(),
@@ -11137,7 +12282,7 @@ const descriptors = ['then', 'catch', 'finally'].map(property => [
11137
12282
  Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property),
11138
12283
  ]);
11139
12284
 
11140
- // Main shared logic for all async methods: `execa()`, `execaCommand()`, `$`, `execaNode()`
12285
+ // Main shared logic for all async methods: `execa()`, `$`, `execaNode()`
11141
12286
  const execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
11142
12287
  const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleAsyncArguments(rawFile, rawArguments, rawOptions);
11143
12288
  const {subprocess, promise} = spawnSubprocessAsync({
@@ -11187,12 +12332,12 @@ const handleAsyncArguments = (rawFile, rawArguments, rawOptions) => {
11187
12332
 
11188
12333
  // Options normalization logic specific to async methods.
11189
12334
  // Prevent passing the `timeout` option directly to `child_process.spawn()`.
11190
- const handleAsyncOptions = ({timeout, signal, cancelSignal, ...options}) => {
12335
+ const handleAsyncOptions = ({timeout, signal, ...options}) => {
11191
12336
  if (signal !== undefined) {
11192
12337
  throw new TypeError('The "signal" option has been renamed to "cancelSignal" instead.');
11193
12338
  }
11194
12339
 
11195
- return {...options, timeoutDuration: timeout, signal: cancelSignal};
12340
+ return {...options, timeoutDuration: timeout};
11196
12341
  };
11197
12342
 
11198
12343
  const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verboseInfo, command, escapedCommand, fileDescriptors}) => {
@@ -11218,15 +12363,18 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
11218
12363
  pipeOutputAsync(subprocess, fileDescriptors, controller);
11219
12364
  cleanupOnExit(subprocess, options, controller);
11220
12365
 
12366
+ const context = {};
11221
12367
  const onInternalError = createDeferred();
11222
12368
  subprocess.kill = subprocessKill.bind(undefined, {
11223
12369
  kill: subprocess.kill.bind(subprocess),
11224
12370
  options,
11225
12371
  onInternalError,
12372
+ context,
11226
12373
  controller,
11227
12374
  });
11228
12375
  subprocess.all = makeAllStream(subprocess, options);
11229
12376
  addConvertedStreams(subprocess, options);
12377
+ addIpcMethods(subprocess, options);
11230
12378
 
11231
12379
  const promise = handlePromise({
11232
12380
  subprocess,
@@ -11237,6 +12385,7 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
11237
12385
  originalStreams,
11238
12386
  command,
11239
12387
  escapedCommand,
12388
+ context,
11240
12389
  onInternalError,
11241
12390
  controller,
11242
12391
  });
@@ -11244,10 +12393,14 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
11244
12393
  };
11245
12394
 
11246
12395
  // Asynchronous logic, as opposed to the previous logic which can be run synchronously, i.e. can be returned to user right away
11247
- const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, onInternalError, controller}) => {
11248
- const context = {timedOut: false};
11249
-
11250
- const [errorInfo, [exitCode, signal], stdioResults, allResult] = await waitForSubprocessResult({
12396
+ const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, context, onInternalError, controller}) => {
12397
+ const [
12398
+ errorInfo,
12399
+ [exitCode, signal],
12400
+ stdioResults,
12401
+ allResult,
12402
+ ipcOutput,
12403
+ ] = await waitForSubprocessResult({
11251
12404
  subprocess,
11252
12405
  options,
11253
12406
  context,
@@ -11268,6 +12421,7 @@ const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileD
11268
12421
  signal,
11269
12422
  stdio,
11270
12423
  all,
12424
+ ipcOutput,
11271
12425
  context,
11272
12426
  options,
11273
12427
  command,
@@ -11277,18 +12431,21 @@ const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileD
11277
12431
  return handleResult(result, verboseInfo, options);
11278
12432
  };
11279
12433
 
11280
- const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, context, options, command, escapedCommand, startTime}) => 'error' in errorInfo
12434
+ const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options, command, escapedCommand, startTime}) => 'error' in errorInfo
11281
12435
  ? makeError({
11282
12436
  error: errorInfo.error,
11283
12437
  command,
11284
12438
  escapedCommand,
11285
- timedOut: context.timedOut,
11286
- isCanceled: options.signal?.aborted === true,
12439
+ timedOut: context.terminationReason === 'timeout',
12440
+ isCanceled: context.terminationReason === 'cancel' || context.terminationReason === 'gracefulCancel',
12441
+ isGracefullyCanceled: context.terminationReason === 'gracefulCancel',
11287
12442
  isMaxBuffer: errorInfo.error instanceof MaxBufferError,
12443
+ isForcefullyTerminated: context.isForcefullyTerminated,
11288
12444
  exitCode,
11289
12445
  signal,
11290
12446
  stdio,
11291
12447
  all,
12448
+ ipcOutput,
11292
12449
  options,
11293
12450
  startTime,
11294
12451
  isSync: false,
@@ -11298,6 +12455,7 @@ const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, context, optio
11298
12455
  escapedCommand,
11299
12456
  stdio,
11300
12457
  all,
12458
+ ipcOutput,
11301
12459
  options,
11302
12460
  startTime,
11303
12461
  });
@@ -11394,8 +12552,23 @@ const parseCommand = (command, unusedArguments) => {
11394
12552
  throw new TypeError(`The command and its arguments must be passed as a single string: ${command} ${unusedArguments}.`);
11395
12553
  }
11396
12554
 
12555
+ const [file, ...commandArguments] = parseCommandString(command);
12556
+ return {file, commandArguments};
12557
+ };
12558
+
12559
+ // Convert `command` string into an array of file or arguments to pass to $`${...fileOrCommandArguments}`
12560
+ const parseCommandString = command => {
12561
+ if (typeof command !== 'string') {
12562
+ throw new TypeError(`The command must be a string: ${String(command)}.`);
12563
+ }
12564
+
12565
+ const trimmedCommand = command.trim();
12566
+ if (trimmedCommand === '') {
12567
+ return [];
12568
+ }
12569
+
11397
12570
  const tokens = [];
11398
- for (const token of command.trim().split(SPACES_REGEXP)) {
12571
+ for (const token of trimmedCommand.split(SPACES_REGEXP)) {
11399
12572
  // Allow spaces to be escaped by a backslash if not meant as a delimiter
11400
12573
  const previousToken = tokens.at(-1);
11401
12574
  if (previousToken && previousToken.endsWith('\\')) {
@@ -11406,8 +12579,7 @@ const parseCommand = (command, unusedArguments) => {
11406
12579
  }
11407
12580
  }
11408
12581
 
11409
- const [file, ...commandArguments] = tokens;
11410
- return {file, commandArguments};
12582
+ return tokens;
11411
12583
  };
11412
12584
 
11413
12585
  const SPACES_REGEXP = / +/g;
@@ -11442,6 +12614,8 @@ createExeca(mapCommandSync);
11442
12614
  createExeca(mapNode);
11443
12615
  createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
11444
12616
 
12617
+ getIpcExport();
12618
+
11445
12619
  var lodash = {exports: {}};
11446
12620
 
11447
12621
  /**
@@ -32272,7 +33446,7 @@ var utils$j = {};
32272
33446
  */
32273
33447
 
32274
33448
  exports.escapeNode = (block, n = 0, type) => {
32275
- let node = block.nodes[n];
33449
+ const node = block.nodes[n];
32276
33450
  if (!node) return;
32277
33451
 
32278
33452
  if ((type && node.type === type) || node.type === 'open' || node.type === 'close') {
@@ -32341,13 +33515,23 @@ var utils$j = {};
32341
33515
 
32342
33516
  exports.flatten = (...args) => {
32343
33517
  const result = [];
33518
+
32344
33519
  const flat = arr => {
32345
33520
  for (let i = 0; i < arr.length; i++) {
32346
- let ele = arr[i];
32347
- Array.isArray(ele) ? flat(ele) : ele !== void 0 && result.push(ele);
33521
+ const ele = arr[i];
33522
+
33523
+ if (Array.isArray(ele)) {
33524
+ flat(ele);
33525
+ continue;
33526
+ }
33527
+
33528
+ if (ele !== undefined) {
33529
+ result.push(ele);
33530
+ }
32348
33531
  }
32349
33532
  return result;
32350
33533
  };
33534
+
32351
33535
  flat(args);
32352
33536
  return result;
32353
33537
  };
@@ -32356,9 +33540,9 @@ var utils$j = {};
32356
33540
  const utils$i = utils$j;
32357
33541
 
32358
33542
  var stringify$4 = (ast, options = {}) => {
32359
- let stringify = (node, parent = {}) => {
32360
- let invalidBlock = options.escapeInvalid && utils$i.isInvalidBrace(parent);
32361
- let invalidNode = node.invalid === true && options.escapeInvalid === true;
33543
+ const stringify = (node, parent = {}) => {
33544
+ const invalidBlock = options.escapeInvalid && utils$i.isInvalidBrace(parent);
33545
+ const invalidNode = node.invalid === true && options.escapeInvalid === true;
32362
33546
  let output = '';
32363
33547
 
32364
33548
  if (node.value) {
@@ -32373,7 +33557,7 @@ var stringify$4 = (ast, options = {}) => {
32373
33557
  }
32374
33558
 
32375
33559
  if (node.nodes) {
32376
- for (let child of node.nodes) {
33560
+ for (const child of node.nodes) {
32377
33561
  output += stringify(child);
32378
33562
  }
32379
33563
  }
@@ -32747,7 +33931,7 @@ const toMaxLen = (input, maxLength) => {
32747
33931
  return negative ? ('-' + input) : input;
32748
33932
  };
32749
33933
 
32750
- const toSequence = (parts, options) => {
33934
+ const toSequence = (parts, options, maxLen) => {
32751
33935
  parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
32752
33936
  parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
32753
33937
 
@@ -32757,11 +33941,11 @@ const toSequence = (parts, options) => {
32757
33941
  let result;
32758
33942
 
32759
33943
  if (parts.positives.length) {
32760
- positives = parts.positives.join('|');
33944
+ positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|');
32761
33945
  }
32762
33946
 
32763
33947
  if (parts.negatives.length) {
32764
- negatives = `-(${prefix}${parts.negatives.join('|')})`;
33948
+ negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`;
32765
33949
  }
32766
33950
 
32767
33951
  if (positives && negatives) {
@@ -32859,7 +34043,7 @@ const fillNumbers = (start, end, step = 1, options = {}) => {
32859
34043
 
32860
34044
  if (options.toRegex === true) {
32861
34045
  return step > 1
32862
- ? toSequence(parts, options)
34046
+ ? toSequence(parts, options, maxLen)
32863
34047
  : toRegex(range, null, { wrap: false, ...options });
32864
34048
  }
32865
34049
 
@@ -32871,7 +34055,6 @@ const fillLetters = (start, end, step = 1, options = {}) => {
32871
34055
  return invalidRange(start, end, options);
32872
34056
  }
32873
34057
 
32874
-
32875
34058
  let format = options.transform || (val => String.fromCharCode(val));
32876
34059
  let a = `${start}`.charCodeAt(0);
32877
34060
  let b = `${end}`.charCodeAt(0);
@@ -32939,30 +34122,32 @@ const fill$1 = fillRange;
32939
34122
  const utils$h = utils$j;
32940
34123
 
32941
34124
  const compile$1 = (ast, options = {}) => {
32942
- let walk = (node, parent = {}) => {
32943
- let invalidBlock = utils$h.isInvalidBrace(parent);
32944
- let invalidNode = node.invalid === true && options.escapeInvalid === true;
32945
- let invalid = invalidBlock === true || invalidNode === true;
32946
- let prefix = options.escapeInvalid === true ? '\\' : '';
34125
+ const walk = (node, parent = {}) => {
34126
+ const invalidBlock = utils$h.isInvalidBrace(parent);
34127
+ const invalidNode = node.invalid === true && options.escapeInvalid === true;
34128
+ const invalid = invalidBlock === true || invalidNode === true;
34129
+ const prefix = options.escapeInvalid === true ? '\\' : '';
32947
34130
  let output = '';
32948
34131
 
32949
34132
  if (node.isOpen === true) {
32950
34133
  return prefix + node.value;
32951
34134
  }
34135
+
32952
34136
  if (node.isClose === true) {
34137
+ console.log('node.isClose', prefix, node.value);
32953
34138
  return prefix + node.value;
32954
34139
  }
32955
34140
 
32956
34141
  if (node.type === 'open') {
32957
- return invalid ? (prefix + node.value) : '(';
34142
+ return invalid ? prefix + node.value : '(';
32958
34143
  }
32959
34144
 
32960
34145
  if (node.type === 'close') {
32961
- return invalid ? (prefix + node.value) : ')';
34146
+ return invalid ? prefix + node.value : ')';
32962
34147
  }
32963
34148
 
32964
34149
  if (node.type === 'comma') {
32965
- return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|');
34150
+ return node.prev.type === 'comma' ? '' : invalid ? node.value : '|';
32966
34151
  }
32967
34152
 
32968
34153
  if (node.value) {
@@ -32970,8 +34155,8 @@ const compile$1 = (ast, options = {}) => {
32970
34155
  }
32971
34156
 
32972
34157
  if (node.nodes && node.ranges > 0) {
32973
- let args = utils$h.reduce(node.nodes);
32974
- let range = fill$1(...args, { ...options, wrap: false, toRegex: true });
34158
+ const args = utils$h.reduce(node.nodes);
34159
+ const range = fill$1(...args, { ...options, wrap: false, toRegex: true, strictZeros: true });
32975
34160
 
32976
34161
  if (range.length !== 0) {
32977
34162
  return args.length > 1 && range.length > 1 ? `(${range})` : range;
@@ -32979,10 +34164,11 @@ const compile$1 = (ast, options = {}) => {
32979
34164
  }
32980
34165
 
32981
34166
  if (node.nodes) {
32982
- for (let child of node.nodes) {
34167
+ for (const child of node.nodes) {
32983
34168
  output += walk(child, node);
32984
34169
  }
32985
34170
  }
34171
+
32986
34172
  return output;
32987
34173
  };
32988
34174
 
@@ -32996,7 +34182,7 @@ const stringify$2 = stringify$4;
32996
34182
  const utils$g = utils$j;
32997
34183
 
32998
34184
  const append = (queue = '', stash = '', enclose = false) => {
32999
- let result = [];
34185
+ const result = [];
33000
34186
 
33001
34187
  queue = [].concat(queue);
33002
34188
  stash = [].concat(stash);
@@ -33006,15 +34192,15 @@ const append = (queue = '', stash = '', enclose = false) => {
33006
34192
  return enclose ? utils$g.flatten(stash).map(ele => `{${ele}}`) : stash;
33007
34193
  }
33008
34194
 
33009
- for (let item of queue) {
34195
+ for (const item of queue) {
33010
34196
  if (Array.isArray(item)) {
33011
- for (let value of item) {
34197
+ for (const value of item) {
33012
34198
  result.push(append(value, stash, enclose));
33013
34199
  }
33014
34200
  } else {
33015
34201
  for (let ele of stash) {
33016
34202
  if (enclose === true && typeof ele === 'string') ele = `{${ele}}`;
33017
- result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele));
34203
+ result.push(Array.isArray(ele) ? append(item, ele, enclose) : item + ele);
33018
34204
  }
33019
34205
  }
33020
34206
  }
@@ -33022,9 +34208,9 @@ const append = (queue = '', stash = '', enclose = false) => {
33022
34208
  };
33023
34209
 
33024
34210
  const expand$1 = (ast, options = {}) => {
33025
- let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit;
34211
+ const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit;
33026
34212
 
33027
- let walk = (node, parent = {}) => {
34213
+ const walk = (node, parent = {}) => {
33028
34214
  node.queue = [];
33029
34215
 
33030
34216
  let p = parent;
@@ -33046,7 +34232,7 @@ const expand$1 = (ast, options = {}) => {
33046
34232
  }
33047
34233
 
33048
34234
  if (node.nodes && node.ranges > 0) {
33049
- let args = utils$g.reduce(node.nodes);
34235
+ const args = utils$g.reduce(node.nodes);
33050
34236
 
33051
34237
  if (utils$g.exceedsLimit(...args, options.step, rangeLimit)) {
33052
34238
  throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
@@ -33062,7 +34248,7 @@ const expand$1 = (ast, options = {}) => {
33062
34248
  return;
33063
34249
  }
33064
34250
 
33065
- let enclose = utils$g.encloseBrace(node);
34251
+ const enclose = utils$g.encloseBrace(node);
33066
34252
  let queue = node.queue;
33067
34253
  let block = node;
33068
34254
 
@@ -33072,7 +34258,7 @@ const expand$1 = (ast, options = {}) => {
33072
34258
  }
33073
34259
 
33074
34260
  for (let i = 0; i < node.nodes.length; i++) {
33075
- let child = node.nodes[i];
34261
+ const child = node.nodes[i];
33076
34262
 
33077
34263
  if (child.type === 'comma' && node.type === 'brace') {
33078
34264
  if (i === 1) queue.push('');
@@ -33104,7 +34290,7 @@ const expand$1 = (ast, options = {}) => {
33104
34290
  var expand_1 = expand$1;
33105
34291
 
33106
34292
  var constants$4 = {
33107
- MAX_LENGTH: 1024 * 64,
34293
+ MAX_LENGTH: 10000,
33108
34294
 
33109
34295
  // Digits
33110
34296
  CHAR_0: '0', /* 0 */
@@ -33192,18 +34378,18 @@ const parse$3 = (input, options = {}) => {
33192
34378
  throw new TypeError('Expected a string');
33193
34379
  }
33194
34380
 
33195
- let opts = options || {};
33196
- let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH$1, opts.maxLength) : MAX_LENGTH$1;
34381
+ const opts = options || {};
34382
+ const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH$1, opts.maxLength) : MAX_LENGTH$1;
33197
34383
  if (input.length > max) {
33198
34384
  throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`);
33199
34385
  }
33200
34386
 
33201
- let ast = { type: 'root', input, nodes: [] };
33202
- let stack = [ast];
34387
+ const ast = { type: 'root', input, nodes: [] };
34388
+ const stack = [ast];
33203
34389
  let block = ast;
33204
34390
  let prev = ast;
33205
34391
  let brackets = 0;
33206
- let length = input.length;
34392
+ const length = input.length;
33207
34393
  let index = 0;
33208
34394
  let depth = 0;
33209
34395
  let value;
@@ -33268,6 +34454,7 @@ const parse$3 = (input, options = {}) => {
33268
34454
 
33269
34455
  if (value === CHAR_LEFT_SQUARE_BRACKET$1) {
33270
34456
  brackets++;
34457
+
33271
34458
  let next;
33272
34459
 
33273
34460
  while (index < length && (next = advance())) {
@@ -33323,7 +34510,7 @@ const parse$3 = (input, options = {}) => {
33323
34510
  */
33324
34511
 
33325
34512
  if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) {
33326
- let open = value;
34513
+ const open = value;
33327
34514
  let next;
33328
34515
 
33329
34516
  if (options.keepQuotes !== true) {
@@ -33355,8 +34542,8 @@ const parse$3 = (input, options = {}) => {
33355
34542
  if (value === CHAR_LEFT_CURLY_BRACE$1) {
33356
34543
  depth++;
33357
34544
 
33358
- let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;
33359
- let brace = {
34545
+ const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;
34546
+ const brace = {
33360
34547
  type: 'brace',
33361
34548
  open: true,
33362
34549
  close: false,
@@ -33383,7 +34570,7 @@ const parse$3 = (input, options = {}) => {
33383
34570
  continue;
33384
34571
  }
33385
34572
 
33386
- let type = 'close';
34573
+ const type = 'close';
33387
34574
  block = stack.pop();
33388
34575
  block.close = true;
33389
34576
 
@@ -33401,7 +34588,7 @@ const parse$3 = (input, options = {}) => {
33401
34588
  if (value === CHAR_COMMA$1 && depth > 0) {
33402
34589
  if (block.ranges > 0) {
33403
34590
  block.ranges = 0;
33404
- let open = block.nodes.shift();
34591
+ const open = block.nodes.shift();
33405
34592
  block.nodes = [open, { type: 'text', value: stringify$1(block) }];
33406
34593
  }
33407
34594
 
@@ -33415,7 +34602,7 @@ const parse$3 = (input, options = {}) => {
33415
34602
  */
33416
34603
 
33417
34604
  if (value === CHAR_DOT$1 && depth > 0 && block.commas === 0) {
33418
- let siblings = block.nodes;
34605
+ const siblings = block.nodes;
33419
34606
 
33420
34607
  if (depth === 0 || siblings.length === 0) {
33421
34608
  push({ type: 'text', value });
@@ -33442,7 +34629,7 @@ const parse$3 = (input, options = {}) => {
33442
34629
  if (prev.type === 'range') {
33443
34630
  siblings.pop();
33444
34631
 
33445
- let before = siblings[siblings.length - 1];
34632
+ const before = siblings[siblings.length - 1];
33446
34633
  before.value += prev.value + value;
33447
34634
  prev = before;
33448
34635
  block.ranges--;
@@ -33475,8 +34662,8 @@ const parse$3 = (input, options = {}) => {
33475
34662
  });
33476
34663
 
33477
34664
  // get the location of the block on parent.nodes (block's siblings)
33478
- let parent = stack[stack.length - 1];
33479
- let index = parent.nodes.indexOf(block);
34665
+ const parent = stack[stack.length - 1];
34666
+ const index = parent.nodes.indexOf(block);
33480
34667
  // replace the (invalid) block with it's nodes
33481
34668
  parent.nodes.splice(index, 1, ...block.nodes);
33482
34669
  }
@@ -33511,8 +34698,8 @@ const braces$1 = (input, options = {}) => {
33511
34698
  let output = [];
33512
34699
 
33513
34700
  if (Array.isArray(input)) {
33514
- for (let pattern of input) {
33515
- let result = braces$1.create(pattern, options);
34701
+ for (const pattern of input) {
34702
+ const result = braces$1.create(pattern, options);
33516
34703
  if (Array.isArray(result)) {
33517
34704
  output.push(...result);
33518
34705
  } else {
@@ -33646,7 +34833,7 @@ braces$1.create = (input, options = {}) => {
33646
34833
  return [input];
33647
34834
  }
33648
34835
 
33649
- return options.expand !== true
34836
+ return options.expand !== true
33650
34837
  ? braces$1.compile(input, options)
33651
34838
  : braces$1.expand(input, options);
33652
34839
  };