in Sources/Confidence/FlagEvaluation.swift [28:133]
func evaluate<T>(
flagName: String,
defaultValue: T,
context: ConfidenceStruct,
flagApplier: FlagApplier? = nil,
debugLogger: DebugLogger? = nil
) -> Evaluation<T> {
do {
let parsedKey = try FlagPath.getPath(for: flagName)
let resolvedFlag = self.flags.first { resolvedFlag in resolvedFlag.flag == parsedKey.flag }
guard let resolvedFlag = resolvedFlag else {
return Evaluation(
value: defaultValue,
variant: nil,
reason: .error,
errorCode: .flagNotFound,
errorMessage: "Flag '\(parsedKey.flag)' not found in local cache"
)
}
if let debugLogger = debugLogger {
debugLogger.logResolveDebugURL(flagName: parsedKey.flag, context: context)
}
if let evaluation = checkBackendErrors(resolvedFlag: resolvedFlag, defaultValue: defaultValue) {
return evaluation
}
guard let value = resolvedFlag.value else {
// No backend error, but nil value returned. This can happend with "noSegmentMatch" or "archived", for example
Task {
await flagApplier?.apply(flagName: parsedKey.flag, resolveToken: self.resolveToken)
}
return Evaluation(
value: defaultValue,
variant: resolvedFlag.variant,
reason: resolvedFlag.resolveReason,
errorCode: nil,
errorMessage: nil
)
}
let parsedValue = try getValue(path: parsedKey.path, value: value)
let typedValue: T? = getTyped(value: parsedValue)
if resolvedFlag.resolveReason == .match {
var resolveReason: ResolveReason = .match
if self.context != context {
resolveReason = .stale
}
if let typedValue = typedValue {
Task {
await flagApplier?.apply(flagName: parsedKey.flag, resolveToken: self.resolveToken)
}
return Evaluation(
value: typedValue,
variant: resolvedFlag.variant,
reason: resolveReason,
errorCode: nil,
errorMessage: nil
)
} else {
// `null` type from backend instructs to use client-side default value
if parsedValue == .init(null: ()) {
Task {
await flagApplier?.apply(flagName: parsedKey.flag, resolveToken: self.resolveToken)
}
return Evaluation(
value: defaultValue,
variant: resolvedFlag.variant,
reason: resolveReason,
errorCode: nil,
errorMessage: nil
)
} else {
return Evaluation(
value: defaultValue,
variant: nil,
reason: .error,
errorCode: .typeMismatch,
errorMessage: nil
)
}
}
} else {
Task {
await flagApplier?.apply(flagName: parsedKey.flag, resolveToken: self.resolveToken)
}
return Evaluation(
value: defaultValue,
variant: resolvedFlag.variant,
reason: resolvedFlag.resolveReason,
errorCode: nil,
errorMessage: nil
)
}
} catch {
return Evaluation(
value: defaultValue,
variant: nil,
reason: .error,
errorCode: .evaluationError,
errorMessage: error.localizedDescription
)
}
}