(appName: string)
| 37 | } |
| 38 | |
| 39 | async function resolveWindowsAppPath(appName: string): Promise<string | null> { |
| 40 | let output: string |
| 41 | try { |
| 42 | output = await execFilePromise("where", [appName]).then((r) => r.stdout.toString()) |
| 43 | } catch { |
| 44 | return null |
| 45 | } |
| 46 | |
| 47 | const paths = output |
| 48 | .split(/\r?\n/) |
| 49 | .map((line) => line.trim()) |
| 50 | .filter((line) => line.length > 0) |
| 51 | |
| 52 | const hasExt = (path: string, ext: string) => extname(path).toLowerCase() === `.${ext}` |
| 53 | |
| 54 | const exe = paths.find((path) => hasExt(path, "exe")) |
| 55 | if (exe) return exe |
| 56 | |
| 57 | const resolveCmd = async (path: string) => { |
| 58 | const content = await readFile(path, "utf8") |
| 59 | for (const token of content.split('"').map((value: string) => value.trim())) { |
| 60 | const lower = token.toLowerCase() |
| 61 | if (!lower.includes(".exe")) continue |
| 62 | |
| 63 | const index = lower.indexOf("%~dp0") |
| 64 | if (index >= 0) { |
| 65 | const base = dirname(path) |
| 66 | const suffix = token.slice(index + 5) |
| 67 | const resolved = suffix |
| 68 | .replace(/\//g, "\\") |
| 69 | .split("\\") |
| 70 | .filter((part: string) => part && part !== ".") |
| 71 | .reduce((current: string, part: string) => { |
| 72 | if (part === "..") return dirname(current) |
| 73 | return join(current, part) |
| 74 | }, base) |
| 75 | |
| 76 | if (await exists(resolved)) return resolved |
| 77 | } |
| 78 | |
| 79 | if (await exists(token)) return token |
| 80 | } |
| 81 | |
| 82 | return null |
| 83 | } |
| 84 | |
| 85 | for (const path of paths) { |
| 86 | if (hasExt(path, "cmd") || hasExt(path, "bat")) { |
| 87 | const resolved = await resolveCmd(path) |
| 88 | if (resolved) return resolved |
| 89 | } |
| 90 | |
| 91 | if (!extname(path)) { |
| 92 | const cmd = `${path}.cmd` |
| 93 | if (await exists(cmd)) { |
| 94 | const resolved = await resolveCmd(cmd) |
| 95 | if (resolved) return resolved |
| 96 | } |
no test coverage detected