///|
pub fn SourceLocation::to_string(self : SourceLocation) -> String {
  self.line.to_string() + ":" + self.column.to_string()
}

///|
pub fn Diagnostic::location_text(self : Diagnostic) -> String {
  match self.location {
    Some(location) => location.to_string()
    None => "-"
  }
}

///|
pub fn Diagnostic::to_text(self : Diagnostic) -> String {
  self.severity.label() +
  " " +
  self.location_text() +
  " " +
  self.path +
  ": " +
  self.message
}

///|
pub fn Diagnostic::to_markdown(self : Diagnostic) -> String {
  "- **" +
  self.severity.label() +
  "** at `" +
  self.path +
  "` (" +
  self.location_text() +
  "): " +
  self.message
}

///|
pub fn Diagnostic::to_json(self : Diagnostic) -> String {
  let location = match self.location {
    Some(value) =>
      "{\"line\": " +
      value.line.to_string() +
      ", \"column\": " +
      value.column.to_string() +
      ", \"offset\": " +
      value.offset.to_string() +
      "}"
    None => "null"
  }
  "{\"severity\": \"" +
  self.severity.label() +
  "\", \"path\": \"" +
  json_escape(self.path) +
  "\", \"message\": \"" +
  json_escape(self.message) +
  "\", \"location\": " +
  location +
  "}"
}

///|
pub fn DiagnosticBag::to_text(self : DiagnosticBag) -> String {
  let lines : Array[String] = []
  for diagnostic in self.sorted().items {
    lines.push(diagnostic.to_text())
  }
  if lines.length() == 0 {
    "no diagnostics"
  } else {
    lines.join("\n")
  }
}

///|
pub fn DiagnosticBag::to_markdown(self : DiagnosticBag) -> String {
  let lines : Array[String] = [
    "## Import diagnostics",
    "",
    "Summary: " + self.summary(),
  ]
  for diagnostic in self.sorted().items {
    lines.push(diagnostic.to_markdown())
  }
  lines.join("\n")
}

///|
pub fn DiagnosticBag::to_json(self : DiagnosticBag) -> String {
  let builder = StringBuilder::new()
  builder.write_string("[\n")
  for i, diagnostic in self.sorted().items {
    if i > 0 {
      builder.write_string(",\n")
    }
    builder.write_string("  ")
    builder.write_string(diagnostic.to_json())
  }
  builder.write_string("\n]\n")
  builder.to_string()
}

///|
pub fn DiagnosticBag::errors(self : DiagnosticBag) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in self.items {
    if diagnostic.severity == DiagnosticSeverity::Error {
      result.push(diagnostic)
    }
  }
  result
}

///|
pub fn DiagnosticBag::warnings(self : DiagnosticBag) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in self.items {
    if diagnostic.severity == DiagnosticSeverity::Warning {
      result.push(diagnostic)
    }
  }
  result
}

///|
pub fn DiagnosticBag::notes(self : DiagnosticBag) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in self.items {
    if diagnostic.severity == DiagnosticSeverity::Note {
      result.push(diagnostic)
    }
  }
  result
}