use std::sync::Arc;
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;
use crate::ir::{AttributeMap, Expression, Span};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct AssumeRole {
pub role_arn_expr: Expression,
pub span: Span,
}
#[derive(Clone, PartialEq, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct ProviderBlock {
pub local_name: Arc<str>,
#[builder(default)]
pub alias: Option<Arc<str>>,
#[builder(default)]
pub source_addr: Option<Arc<str>>,
#[builder(default)]
pub region_expr: Option<Expression>,
#[builder(default)]
pub profile_expr: Option<Expression>,
#[builder(default)]
pub assume_role: Option<AssumeRole>,
#[builder(default)]
pub raw: AttributeMap,
pub span: Span,
}
impl std::fmt::Debug for ProviderBlock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProviderBlock")
.field("local_name", &self.local_name)
.field("alias", &self.alias)
.field("source_addr", &self.source_addr)
.field("region_expr", &self.region_expr.as_ref().map(|_| "<expr>"))
.field(
"profile_expr",
&self.profile_expr.as_ref().map(|_| "<expr>"),
)
.field(
"assume_role",
&self.assume_role.as_ref().map(|_| "<assume_role>"),
)
.field(
"raw",
&format!("<{} attributes (redacted)>", self.raw.len()),
)
.field("span", &self.span)
.finish()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, TypedBuilder)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(setter(into)))]
pub struct ProviderRef {
pub local_name: Arc<str>,
#[builder(default)]
pub alias: Option<Arc<str>>,
pub span: Span,
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use std::sync::Arc;
use super::*;
use crate::ir::Span;
#[test]
fn test_should_build_minimal_provider_block() {
let p = ProviderBlock::builder()
.local_name(Arc::<str>::from("aws"))
.span(Span::synthetic())
.build();
assert_eq!(&*p.local_name, "aws");
assert!(p.alias.is_none());
assert!(p.raw.is_empty());
}
#[test]
fn test_should_redact_raw_attrs_in_debug() {
let p = ProviderBlock::builder()
.local_name(Arc::<str>::from("aws"))
.raw(vec![(
Arc::<str>::from("secret_access_key"),
crate::ir::Expression::Literal(crate::ir::Value::Str(Arc::<str>::from(
"very-secret",
))),
)])
.span(Span::synthetic())
.build();
let debug = format!("{p:?}");
assert!(!debug.contains("very-secret"), "{debug}");
assert!(debug.contains("redacted"), "{debug}");
}
#[test]
fn test_should_serde_round_trip_provider_ref() {
let r = ProviderRef {
local_name: Arc::<str>::from("aws"),
alias: Some(Arc::<str>::from("main")),
span: Span::synthetic(),
};
let json = serde_json::to_string(&r).unwrap();
let back: ProviderRef = serde_json::from_str(&json).unwrap();
assert_eq!(r, back);
}
}