///|
pub fn issues_text(issues : Array[CanonicalIssue]) -> String {
  if issues.length() == 0 {
    return "no semantic canonicalization issues"
  }
  let mut output = ""
  for issue in issues {
    if output != "" {
      output = output + "\n"
    }
    output = output + issue.to_text()
  }
  output
}

///|
pub fn profile_text(profile : JsonProfile) -> String {
  "values: " +
  profile.stats.value_count.to_string() +
  "\nkeys: " +
  profile.key_count.to_string() +
  " (unique " +
  profile.unique_key_count.to_string() +
  ")\nmax key length: " +
  profile.max_key_length.to_string() +
  "\nmax string length: " +
  profile.max_string_length.to_string() +
  "\nnegative zero tokens: " +
  profile.negative_zero_count.to_string() +
  "\ncanonical issues: " +
  profile.canonical_issue_count.to_string()
}