| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 | '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;};
 |