add JsonLines support

This commit is contained in:
Brent Westbrook 2025-07-04 11:07:03 -04:00
parent 9648beebce
commit ae467c372a
4 changed files with 70 additions and 49 deletions

View file

@ -1237,7 +1237,14 @@ pub enum DiagnosticFormat {
/// [Azure Pipelines]: https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#logissue-log-an-error-or-warning
Azure,
/// Print diagnostics in JSON format.
///
/// Unlike `json-lines`, this prints all of the diagnostics as a JSON array.
Json,
/// Print diagnostics in JSON format, one per line.
///
/// This will print each diagnostic as a separate JSON object on its own line. See the `json`
/// format for an array of all diagnostics.
JsonLines,
}
impl DiagnosticFormat {

View file

@ -63,52 +63,6 @@ impl<'a> DisplayDiagnostic<'a> {
}
}
/// A type that implements `std::fmt::Display` for rendering a collection of diagnostics.
///
/// It intended for collections of diagnostics that need to be serialized together, as is the case
/// for JSON, for example.
///
/// See [`DisplayDiagnostic`] for rendering individual `Diagnostic`s and details about the lifetime
/// constraints.
pub struct DisplayDiagnostics<'a> {
config: &'a DisplayDiagnosticConfig,
resolver: &'a dyn FileResolver,
diagnostics: &'a [Diagnostic],
}
impl<'a> DisplayDiagnostics<'a> {
pub fn new(
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
diagnostics: &'a [Diagnostic],
) -> DisplayDiagnostics<'a> {
DisplayDiagnostics {
config,
resolver,
diagnostics,
}
}
}
impl std::fmt::Display for DisplayDiagnostics<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.config.format {
DiagnosticFormat::Concise | DiagnosticFormat::Azure | DiagnosticFormat::Full => {
for diag in self.diagnostics {
write!(f, "{}", diag.display(self.resolver, self.config))?;
}
}
DiagnosticFormat::Json => write!(
f,
"{:#}",
diagnostics_to_json_value(self.diagnostics, self.resolver)
)?,
}
Ok(())
}
}
impl std::fmt::Display for DisplayDiagnostic<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let stylesheet = if self.config.color {
@ -187,11 +141,15 @@ impl std::fmt::Display for DisplayDiagnostic<'_> {
body = self.diag.body(),
)?;
}
DiagnosticFormat::Json => {
DiagnosticFormat::JsonLines => {
if let Some(value) = message_to_json_value(self.diag, self.resolver) {
writeln!(f, "{value}")?;
}
}
DiagnosticFormat::Json => {
let value = diagnostics_to_json_value(std::iter::once(self.diag), self.resolver);
writeln!(f, "{value}")?;
}
DiagnosticFormat::Full => {
let mut renderer = self.annotate_renderer.clone();
renderer = renderer
@ -217,6 +175,55 @@ impl std::fmt::Display for DisplayDiagnostic<'_> {
}
}
/// A type that implements `std::fmt::Display` for rendering a collection of diagnostics.
///
/// It intended for collections of diagnostics that need to be serialized together, as is the case
/// for JSON, for example.
///
/// See [`DisplayDiagnostic`] for rendering individual `Diagnostic`s and details about the lifetime
/// constraints.
pub struct DisplayDiagnostics<'a> {
config: &'a DisplayDiagnosticConfig,
resolver: &'a dyn FileResolver,
diagnostics: &'a [Diagnostic],
}
impl<'a> DisplayDiagnostics<'a> {
pub fn new(
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
diagnostics: &'a [Diagnostic],
) -> DisplayDiagnostics<'a> {
DisplayDiagnostics {
config,
resolver,
diagnostics,
}
}
}
impl std::fmt::Display for DisplayDiagnostics<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.config.format {
DiagnosticFormat::Concise
| DiagnosticFormat::Azure
| DiagnosticFormat::Full
| DiagnosticFormat::JsonLines => {
for diag in self.diagnostics {
write!(f, "{}", diag.display(self.resolver, self.config))?;
}
}
DiagnosticFormat::Json => write!(
f,
"{:#}",
diagnostics_to_json_value(self.diagnostics, self.resolver)
)?,
}
Ok(())
}
}
/// A sequence of resolved diagnostics.
///
/// Resolving a diagnostic refers to the process of restructuring its internal

View file

@ -14,7 +14,7 @@ impl Emitter for JsonLinesEmitter {
diagnostics: &[Diagnostic],
context: &EmitterContext,
) -> anyhow::Result<()> {
let config = DisplayDiagnosticConfig::default().format(DiagnosticFormat::Json);
let config = DisplayDiagnosticConfig::default().format(DiagnosticFormat::JsonLines);
for diagnostic in diagnostics {
write!(writer, "{}", diagnostic.display(context, &config))?;
}

9
ty.schema.json generated
View file

@ -83,11 +83,18 @@
]
},
{
"description": "Print diagnostics in JSON format.",
"description": "Print diagnostics in JSON format.\n\nUnlike `json-lines`, this prints all of the diagnostics as a JSON array.",
"type": "string",
"enum": [
"json"
]
},
{
"description": "Print diagnostics in JSON format, one per line.\n\nThis will print each diagnostic as a separate JSON object on its own line. See the `json` format for an array of all diagnostics.",
"type": "string",
"enum": [
"json-lines"
]
}
]
},