| 'use strict'; | 
| const {promisify} = require('util'); | 
| const path = require('path'); | 
| const childProcess = require('child_process'); | 
| const fs = require('fs'); | 
| const isWsl = require('is-wsl'); | 
|   | 
| const pAccess = promisify(fs.access); | 
| const pExecFile = promisify(childProcess.execFile); | 
|   | 
| // Path to included `xdg-open` | 
| const localXdgOpenPath = path.join(__dirname, 'xdg-open'); | 
|   | 
| // Convert a path from WSL format to Windows format: | 
| // `/mnt/c/Program Files/Example/MyApp.exe` → `C:\Program Files\Example\MyApp.exe` | 
| const wslToWindowsPath = async path => { | 
|     const {stdout} = await pExecFile('wslpath', ['-w', path]); | 
|     return stdout.trim(); | 
| }; | 
|   | 
| module.exports = async (target, options) => { | 
|     if (typeof target !== 'string') { | 
|         throw new TypeError('Expected a `target`'); | 
|     } | 
|   | 
|     options = { | 
|         wait: false, | 
|         background: false, | 
|         ...options | 
|     }; | 
|   | 
|     let command; | 
|     let appArguments = []; | 
|     const cliArguments = []; | 
|     const childProcessOptions = {}; | 
|   | 
|     if (Array.isArray(options.app)) { | 
|         appArguments = options.app.slice(1); | 
|         options.app = options.app[0]; | 
|     } | 
|   | 
|     if (process.platform === 'darwin') { | 
|         command = 'open'; | 
|   | 
|         if (options.wait) { | 
|             cliArguments.push('--wait-apps'); | 
|         } | 
|   | 
|         if (options.background) { | 
|             cliArguments.push('--background'); | 
|         } | 
|   | 
|         if (options.app) { | 
|             cliArguments.push('-a', options.app); | 
|         } | 
|     } else if (process.platform === 'win32' || isWsl) { | 
|         command = 'cmd' + (isWsl ? '.exe' : ''); | 
|         cliArguments.push('/c', 'start', '""', '/b'); | 
|         target = target.replace(/&/g, '^&'); | 
|   | 
|         if (options.wait) { | 
|             cliArguments.push('/wait'); | 
|         } | 
|   | 
|         if (options.app) { | 
|             if (isWsl && options.app.startsWith('/mnt/')) { | 
|                 const windowsPath = await wslToWindowsPath(options.app); | 
|                 options.app = windowsPath; | 
|             } | 
|   | 
|             cliArguments.push(options.app); | 
|         } | 
|   | 
|         if (appArguments.length > 0) { | 
|             cliArguments.push(...appArguments); | 
|         } | 
|     } else { | 
|         if (options.app) { | 
|             command = options.app; | 
|         } else { | 
|             // When bundled by Webpack, there's no actual package file path and no local `xdg-open`. | 
|             const isBundled = !__dirname || __dirname === '/'; | 
|   | 
|             // Check if local `xdg-open` exists and is executable. | 
|             let exeLocalXdgOpen = false; | 
|             try { | 
|                 await pAccess(localXdgOpenPath, fs.constants.X_OK); | 
|                 exeLocalXdgOpen = true; | 
|             } catch (error) {} | 
|   | 
|             const useSystemXdgOpen = process.versions.electron || | 
|                 process.platform === 'android' || isBundled || !exeLocalXdgOpen; | 
|             command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath; | 
|         } | 
|   | 
|         if (appArguments.length > 0) { | 
|             cliArguments.push(...appArguments); | 
|         } | 
|   | 
|         if (!options.wait) { | 
|             // `xdg-open` will block the process unless stdio is ignored | 
|             // and it's detached from the parent even if it's unref'd. | 
|             childProcessOptions.stdio = 'ignore'; | 
|             childProcessOptions.detached = true; | 
|         } | 
|     } | 
|   | 
|     cliArguments.push(target); | 
|   | 
|     if (process.platform === 'darwin' && appArguments.length > 0) { | 
|         cliArguments.push('--args', ...appArguments); | 
|     } | 
|   | 
|     const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions); | 
|   | 
|     if (options.wait) { | 
|         return new Promise((resolve, reject) => { | 
|             subprocess.once('error', reject); | 
|   | 
|             subprocess.once('close', exitCode => { | 
|                 if (exitCode > 0) { | 
|                     reject(new Error(`Exited with code ${exitCode}`)); | 
|                     return; | 
|                 } | 
|   | 
|                 resolve(subprocess); | 
|             }); | 
|         }); | 
|     } | 
|   | 
|     subprocess.unref(); | 
|   | 
|     return subprocess; | 
| }; |