///|
fn source_to_text(source : Source) -> String {
  source.raw
}

///|
fn directive_to_text(directive : Directive) -> String {
  let parts : Array[String] = []
  parts.push(directive.name)
  for source in directive.sources {
    parts.push(source_to_text(source))
  }
  join_strings(parts, " ")
}

///|
/// Serialize a parsed policy into stable, normalized CSP text.
pub fn normalize(policy : Policy) -> String {
  let parts : Array[String] = []
  for directive in policy.directives {
    parts.push(directive_to_text(directive))
  }
  join_strings(parts, "; ")
}

///|
/// Render findings as line-oriented text for CLI and CI logs.
pub fn findings_text(findings : Array[Finding]) -> String {
  let lines : Array[String] = []
  for finding in findings {
    lines.push(
      severity_to_string(finding.severity) +
      " " +
      finding.code +
      " " +
      finding.directive +
      " line=" +
      finding.line.to_string() +
      ": " +
      finding.message,
    )
  }
  join_strings(lines, "\n")
}

///|
/// Return a compact summary for examples.
pub fn summary(policy : Policy) -> String {
  "directives=" +
  policy.directives.length().to_string() +
  ", findings=" +
  policy.diagnostics.length().to_string() +
  ", names=" +
  join_strings(directive_names(policy), ",")
}