'a'
mh-two-thousand-and-two
2024-04-12 44d2c92345cd156a59fc327b3060292a282d2893
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
'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;
};