1+ import { fileURLToPath } from 'node:url'
12import which from '@zkochan/which'
23import { execa , execaSync } from 'execa'
34import type { Options , SyncOptions , ResultPromise , SyncResult } from 'execa'
@@ -7,22 +8,29 @@ export type { Options, SyncOptions, ResultPromise, SyncResult }
78
89const pathCache = new Map < string , string | undefined > ( )
910
11+ function cwdToString ( cwd : string | URL | undefined ) : string {
12+ if ( cwd == null ) return process . cwd ( )
13+ if ( cwd instanceof URL ) return fileURLToPath ( cwd )
14+ return cwd
15+ }
16+
1017export function sync (
1118 file : string ,
1219 args ?: readonly string [ ] ,
1320 options ?: SyncOptions
1421) : SyncResult {
22+ const normalizedArgs = args ? [ ...args ] : [ ]
1523 try {
16- which . sync ( file , { path : options ?. cwd as string ?? process . cwd ( ) } )
24+ which . sync ( file , { path : cwdToString ( options ?. cwd ) } )
1725 } catch ( err : any ) {
1826 // If the command is not found in the current directory, there is no need to resolve the command to full location
1927 // as there is no danger of binary planting attack on Windows
2028 if ( err . code === 'ENOENT' ) {
21- return execaSync ( file , args as string [ ] , options )
29+ return execaSync ( file , normalizedArgs , options )
2230 }
2331 }
2432 const fileAbsolutePath = getCommandAbsolutePathSync ( file , options )
25- return execaSync ( fileAbsolutePath , args as string [ ] , options )
33+ return execaSync ( fileAbsolutePath , normalizedArgs , options )
2634}
2735
2836function getCommandAbsolutePathSync ( file : string , options ?: {
@@ -47,15 +55,16 @@ export function safeExeca (
4755 args ?: readonly string [ ] ,
4856 options ?: Options
4957) : ResultPromise {
58+ const normalizedArgs = args ? [ ...args ] : [ ]
5059 try {
51- which . sync ( file , { path : options ?. cwd as string ?? process . cwd ( ) } )
60+ which . sync ( file , { path : cwdToString ( options ?. cwd ) } )
5261 } catch ( err : any ) {
5362 // If the command is not found in the current directory, there is no need to resolve the command to full location
5463 // as there is no danger of binary planting attack on Windows
5564 if ( err . code === 'ENOENT' ) {
56- return execa ( file , args as string [ ] , options )
65+ return execa ( file , normalizedArgs , options )
5766 }
5867 }
5968 const fileAbsolutePath = getCommandAbsolutePathSync ( file , options )
60- return execa ( fileAbsolutePath , args as string [ ] , options )
69+ return execa ( fileAbsolutePath , normalizedArgs , options )
6170}
0 commit comments