85 lines
3 KiB
JavaScript
85 lines
3 KiB
JavaScript
'use strict'
|
|
|
|
const path = require('path')
|
|
const fs = require('fs')
|
|
|
|
// Command-line parsing shared by boot and the single-instance handoff.
|
|
// Supported: --launch <id>, --file <path>, --open <path>, or a bare file path.
|
|
// Electron re-serializes handoff argv, so options/positionals match in order.
|
|
|
|
const VALUE_OPTIONS = ['--launch', '--file', '--open']
|
|
|
|
// Value options, the positionals that follow the switches, and inline
|
|
// `--name=value` pairs. Tokens before the first switch are the executable
|
|
// (matched against the running app path in dev mode and skipped).
|
|
function splitArgv(argv) {
|
|
const options = []
|
|
const positional = []
|
|
const inline = new Map()
|
|
const appPath = process.defaultApp && process.argv[1] ? path.resolve(process.argv[1]) : null
|
|
let switched = false
|
|
for (const arg of Array.isArray(argv) ? argv : []) {
|
|
if (typeof arg !== 'string' || !arg) continue
|
|
if (arg.startsWith('-')) {
|
|
switched = true
|
|
const eq = arg.indexOf('=')
|
|
const name = eq === -1 ? arg : arg.slice(0, eq)
|
|
if (!VALUE_OPTIONS.includes(name)) continue
|
|
if (eq === -1) options.push(name)
|
|
else inline.set(name, arg.slice(eq + 1))
|
|
continue
|
|
}
|
|
// absolute in the handed-over argv, possibly relative here
|
|
if (appPath && path.resolve(arg) === appPath) continue
|
|
if (switched) positional.push(arg)
|
|
}
|
|
return { options, positional, inline }
|
|
}
|
|
|
|
// An option's value: inline `--name=value`, or the positional at the same
|
|
// in-order position among the value options.
|
|
function optionValue(parsed, name) {
|
|
if (parsed.inline.has(name)) return parsed.inline.get(name)
|
|
const index = parsed.options.indexOf(name)
|
|
if (index === -1) return null
|
|
const value = parsed.positional[index]
|
|
return value === undefined ? null : value
|
|
}
|
|
|
|
// The file an app shortcut was asked to open; only an absolute path counts.
|
|
const FIELD_CODE_RE = /^%[fFuUdDnNickvm]?$/
|
|
function launchFileOf(parsed, launchId) {
|
|
const explicit = optionValue(parsed, '--file')
|
|
// a literal %f token is never a file path
|
|
if (explicit && !FIELD_CODE_RE.test(explicit) && path.isAbsolute(explicit)) return explicit
|
|
if (!launchId) return null
|
|
for (let i = parsed.positional.length - 1; i >= 0; i--) {
|
|
const arg = parsed.positional[i]
|
|
if (!path.isAbsolute(arg)) continue
|
|
try {
|
|
if (fs.statSync(arg).isFile()) return arg
|
|
} catch {}
|
|
}
|
|
return null
|
|
}
|
|
|
|
function parseArgv(argv) {
|
|
const args = Array.isArray(argv) ? argv : process.argv
|
|
const parsed = splitArgv(args)
|
|
const launchId = optionValue(parsed, '--launch')
|
|
const launchFile = launchFileOf(parsed, launchId)
|
|
let openPath = optionValue(parsed, '--open')
|
|
if (!openPath && !launchId) {
|
|
// Exec %f: the file path arrives as the only non-flag argument
|
|
const bare = args.find(
|
|
a =>
|
|
!a.startsWith('-') &&
|
|
/\.(exe|msi|bat|cmd|lnk)$/i.test(a) &&
|
|
!/\b(electron|olcxja\.plwl)(\.exe)?$/i.test(a)
|
|
)
|
|
if (bare) openPath = bare
|
|
}
|
|
return { launchId, openPath, launchFile }
|
|
}
|
|
|
|
module.exports = { parseArgv }
|