///|
fn structured_escape(value : String) -> String {
  let builder = StringBuilder()
  for character in value {
    match character {
      '"' => builder.write_string("\\\"")
      '\\' => builder.write_string("\\\\")
      '\n' => builder.write_string("\\n")
      '\r' => builder.write_string("\\r")
      '\t' => builder.write_string("\\t")
      _ => builder.write_char(character)
    }
  }
  builder.to_string()
}

///|
/// Render a stable machine-readable report around diagnostics from one source.
pub fn render_report_json(
  diagnostics : Array[Diagnostic],
  source : @source.SourceFile,
  file_name : String,
) -> String {
  let errors = diagnostics.filter(fn(item) { item.severity is Error }).length()
  let warnings = diagnostics
    .filter(fn(item) { item.severity is Warning })
    .length()
  let builder = StringBuilder()
  builder.write_string("{\"file\":\"")
  builder.write_string(
    structured_escape(
      if file_name.is_empty() {
        source.name()
      } else {
        file_name
      },
    ),
  )
  builder.write_string("\",\"count\":")
  builder.write_object(diagnostics.length())
  builder.write_string(",\"errors\":")
  builder.write_object(errors)
  builder.write_string(",\"warnings\":")
  builder.write_object(warnings)
  builder.write_string(",\"diagnostics\":[")
  for index, diagnostic in diagnostics {
    if index > 0 {
      builder.write_char(',')
    }
    builder.write_string("{\"code\":\"")
    builder.write_string(structured_escape(diagnostic.code))
    builder.write_string("\",\"severity\":\"")
    builder.write_string(diagnostic.severity.label())
    builder.write_string("\",\"message\":\"")
    builder.write_string(structured_escape(diagnostic.message))
    builder.write_string("\"}")
  }
  builder.write_string("]}\n")
  builder.to_string()
}