execFileNoThrowPortable.ts
1 import { type Options as ExecaOptions, execaSync } from 'execa' 2 import { getCwd } from '../utils/cwd.js' 3 import { slowLogging } from './slowOperations.js' 4 5 const MS_IN_SECOND = 1000 6 const SECONDS_IN_MINUTE = 60 7 8 type ExecSyncOptions = { 9 abortSignal?: AbortSignal 10 timeout?: number 11 input?: string 12 stdio?: ExecaOptions['stdio'] 13 } 14 15 /** 16 * @deprecated Use `execa` directly with `{ shell: true, reject: false }` for non-blocking execution. 17 * Sync exec calls block the event loop and cause performance issues. 18 */ 19 export function execSyncWithDefaults_DEPRECATED(command: string): string | null 20 /** 21 * @deprecated Use `execa` directly with `{ shell: true, reject: false }` for non-blocking execution. 22 * Sync exec calls block the event loop and cause performance issues. 23 */ 24 export function execSyncWithDefaults_DEPRECATED( 25 command: string, 26 options: ExecSyncOptions, 27 ): string | null 28 /** 29 * @deprecated Use `execa` directly with `{ shell: true, reject: false }` for non-blocking execution. 30 * Sync exec calls block the event loop and cause performance issues. 31 */ 32 export function execSyncWithDefaults_DEPRECATED( 33 command: string, 34 abortSignal: AbortSignal, 35 timeout?: number, 36 ): string | null 37 /** 38 * @deprecated Use `execa` directly with `{ shell: true, reject: false }` for non-blocking execution. 39 * Sync exec calls block the event loop and cause performance issues. 40 */ 41 export function execSyncWithDefaults_DEPRECATED( 42 command: string, 43 optionsOrAbortSignal?: ExecSyncOptions | AbortSignal, 44 timeout = 10 * SECONDS_IN_MINUTE * MS_IN_SECOND, 45 ): string | null { 46 let options: ExecSyncOptions 47 48 if (optionsOrAbortSignal === undefined) { 49 // No second argument - use defaults 50 options = {} 51 } else if (optionsOrAbortSignal instanceof AbortSignal) { 52 // Old signature - second argument is AbortSignal 53 options = { 54 abortSignal: optionsOrAbortSignal, 55 timeout, 56 } 57 } else { 58 // New signature - second argument is options object 59 options = optionsOrAbortSignal 60 } 61 62 const { 63 abortSignal, 64 timeout: finalTimeout = 10 * SECONDS_IN_MINUTE * MS_IN_SECOND, 65 input, 66 stdio = ['ignore', 'pipe', 'pipe'], 67 } = options 68 69 abortSignal?.throwIfAborted() 70 using _ = slowLogging`exec: ${command.slice(0, 200)}` 71 try { 72 const result = execaSync(command, { 73 env: process.env, 74 maxBuffer: 1_000_000, 75 timeout: finalTimeout, 76 cwd: getCwd(), 77 stdio, 78 shell: true, // execSync typically runs shell commands 79 reject: false, // Don't throw on non-zero exit codes 80 input, 81 }) 82 if (!result.stdout) { 83 return null 84 } 85 return result.stdout.trim() || null 86 } catch { 87 return null 88 } 89 }