tv-anarchy/Sources/TVAnarchyCore/CommandTemplate.swift

35 lines
1.6 KiB
Swift
Raw Permalink Normal View History

import Foundation
/// Renders a per-host command template (an argv array from hosts.json) into a
/// single remote command string. Tokens are either literals or placeholders:
/// `{name}` required; substituted with `subs[name]` (empty if absent)
/// `{name?}` optional; the whole word is dropped if the value is nil/empty
/// Every emitted word is single-quote-escaped, so titles/paths with spaces,
/// quotes, or `$` can never break out into shell syntax (argv-array semantics:
/// one array element exactly one shell word).
public enum CommandTemplate {
public static func render(_ template: [String], _ subs: [String: String?]) -> String {
var words: [String] = []
for token in template {
if let ph = placeholder(token) {
let value = subs[ph.name] ?? nil
if ph.optional, value == nil || value!.isEmpty { continue }
words.append(value ?? "")
} else {
words.append(token)
}
}
return words.map(SSHTransport.shq).joined(separator: " ")
}
/// "{name}" (name,false); "{name?}" (name,true); otherwise nil (literal).
static func placeholder(_ token: String) -> (name: String, optional: Bool)? {
guard token.hasPrefix("{"), token.hasSuffix("}") else { return nil }
var inner = String(token.dropFirst().dropLast())
let optional = inner.hasSuffix("?")
if optional { inner = String(inner.dropLast()) }
guard !inner.isEmpty else { return nil }
return (inner, optional)
}
}