///|
pub(all) struct ResolveContext {
host : String
original_host : String
port : Int
remote_user : String?
local_user : String?
home : String?
local_hostname : String?
tags : Array[String]
} derive(Debug, Eq)
///|
pub fn ResolveContext::new(
host : String,
port? : Int = 22,
remote_user? : String,
local_user? : String,
home? : String,
local_hostname? : String,
tags? : Array[String] = [],
) -> ResolveContext {
{
host,
original_host: host,
port,
remote_user,
local_user,
home,
local_hostname,
tags,
}
}
///|
pub(all) struct ResolvedValue {
keyword : String
value : String
raw : String
expanded : String
source : @syntax.SourceLocation
matched_patterns : ReadOnlyArray[String]
} derive(Debug, Eq)
///|
/// The result of applying one directive candidate. The trace is ordered by
/// source order and is suitable for explain and lint without re-running the
/// resolver.
pub(all) enum TraceDecision {
Accepted
Appended
Shadowed
Rejected
Unsupported
} derive(Debug, Eq)
///|
pub(all) struct TraceEvent {
keyword : String
raw : String
expanded : String?
source : @syntax.SourceLocation
matched_patterns : ReadOnlyArray[String]
decision : TraceDecision
message : String?
} derive(Debug, Eq)
///|
pub(all) struct ResolveOutcome {
config : ResolvedConfig
trace : ReadOnlyArray[TraceEvent]
} derive(Debug, Eq)
///|
pub struct ResolvedConfig {
values : Map[String, ResolvedValue]
ordered : Array[ResolvedValue]
} derive(Debug, Eq)
///|
pub fn ResolvedConfig::get(
self : ResolvedConfig,
keyword : String,
) -> ResolvedValue? {
self.values.get(canonical_keyword(keyword))
}
///|
pub fn ResolvedConfig::entries(self : ResolvedConfig) -> Array[ResolvedValue] {
self.ordered.copy()
}
///|
/// Return every final value for a directive. Append directives keep source
/// order; scalar directives return at most one value.
pub fn ResolvedConfig::get_all(
self : ResolvedConfig,
keyword : String,
) -> Array[ResolvedValue] {
let result : Array[ResolvedValue] = []
let normalized = canonical_keyword(keyword)
for value in self.ordered {
if value.keyword == normalized {
result.push(value)
}
}
result
}
///|
pub fn ResolveOutcome::events(self : ResolveOutcome) -> Array[TraceEvent] {
[
for event in self.trace => event
]
}
///|
/// Return whether evaluation recorded an invalid supported directive. Unknown
/// directives are intentionally `Unsupported`, not errors, so callers can
/// choose a compatibility or lint policy without losing the parsed config.
pub fn ResolveOutcome::has_rejections(self : ResolveOutcome) -> Bool {
for event in self.trace {
if event.decision == Rejected {
return true
}
}
false
}
///|
pub(all) suberror ResolveError {
InvalidPort(value~ : String, source~ : @syntax.SourceLocation)
UnsupportedToken(
token~ : String,
keyword~ : String,
source~ : @syntax.SourceLocation
)
MissingTokenContext(
token~ : String,
keyword~ : String,
source~ : @syntax.SourceLocation
)
InvalidDirectiveValue(
keyword~ : String,
value~ : String,
message~ : String,
source~ : @syntax.SourceLocation
)
UnsupportedMatchCondition(name~ : String, source~ : @syntax.SourceLocation)
} derive(Debug, Eq)