1*edeec536SEvan Baconimport * as osascript from '@expo/osascript';
2*edeec536SEvan Baconimport { spawn, type ChildProcess } from 'child_process';
3*edeec536SEvan Baconimport { sync as globSync } from 'glob';
4*edeec536SEvan Baconimport path from 'path';
5*edeec536SEvan Bacon
6*edeec536SEvan Baconimport {
7*edeec536SEvan Bacon  LaunchBrowserTypes,
8*edeec536SEvan Bacon  type LaunchBrowserImpl,
9*edeec536SEvan Bacon  type LaunchBrowserInstance,
10*edeec536SEvan Bacon} from './LaunchBrowser.types';
11*edeec536SEvan Bacon
12*edeec536SEvan Bacon/**
13*edeec536SEvan Bacon * Browser implementation for macOS
14*edeec536SEvan Bacon */
15*edeec536SEvan Baconexport default class LaunchBrowserImplMacOS implements LaunchBrowserImpl, LaunchBrowserInstance {
16*edeec536SEvan Bacon  private _process: ChildProcess | undefined;
17*edeec536SEvan Bacon
18*edeec536SEvan Bacon  MAP = {
19*edeec536SEvan Bacon    [LaunchBrowserTypes.CHROME]: 'google chrome',
20*edeec536SEvan Bacon    [LaunchBrowserTypes.EDGE]: 'microsoft edge',
21*edeec536SEvan Bacon  };
22*edeec536SEvan Bacon
23*edeec536SEvan Bacon  async isSupportedBrowser(browserType: LaunchBrowserTypes): Promise<boolean> {
24*edeec536SEvan Bacon    let result = false;
25*edeec536SEvan Bacon    try {
26*edeec536SEvan Bacon      await osascript.execAsync(`id of application "${this.MAP[browserType]}"`);
27*edeec536SEvan Bacon      result = true;
28*edeec536SEvan Bacon    } catch {
29*edeec536SEvan Bacon      result = false;
30*edeec536SEvan Bacon    }
31*edeec536SEvan Bacon    return result;
32*edeec536SEvan Bacon  }
33*edeec536SEvan Bacon
34*edeec536SEvan Bacon  async createTempBrowserDir(baseDirName: string) {
35*edeec536SEvan Bacon    return path.join(require('temp-dir'), baseDirName);
36*edeec536SEvan Bacon  }
37*edeec536SEvan Bacon
38*edeec536SEvan Bacon  async launchAsync(
39*edeec536SEvan Bacon    browserType: LaunchBrowserTypes,
40*edeec536SEvan Bacon    args: string[]
41*edeec536SEvan Bacon  ): Promise<LaunchBrowserInstance> {
42*edeec536SEvan Bacon    const appDirectory = await osascript.execAsync(
43*edeec536SEvan Bacon      `POSIX path of (path to application "${this.MAP[browserType]}")`
44*edeec536SEvan Bacon    );
45*edeec536SEvan Bacon    const appPath = globSync('Contents/MacOS/*', { cwd: appDirectory.trim(), absolute: true })?.[0];
46*edeec536SEvan Bacon    if (!appPath) {
47*edeec536SEvan Bacon      throw new Error(`Cannot find application path from ${appDirectory}Contents/MacOS`);
48*edeec536SEvan Bacon    }
49*edeec536SEvan Bacon    this._process = spawn(appPath, args, { stdio: 'ignore' });
50*edeec536SEvan Bacon
51*edeec536SEvan Bacon    return this;
52*edeec536SEvan Bacon  }
53*edeec536SEvan Bacon
54*edeec536SEvan Bacon  async close(): Promise<void> {
55*edeec536SEvan Bacon    this._process?.kill();
56*edeec536SEvan Bacon    this._process = undefined;
57*edeec536SEvan Bacon  }
58*edeec536SEvan Bacon}
59