perf(oxlint): render JSON report into a single buffer (#25295)

AI Disclosure: Generated with Claude Code, Opus 5. Reviewed and tested by me.

## What

`format_json` rendered each diagnostic into its own `String`, collected them into a `Vec<String>`, then `join`ed them. That allocates once per diagnostic and copies the entire report a second time to build the joined result.

This renders straight into one output buffer instead.

## Why

On the vscode corpus with `-D all` — 1.37M diagnostics, ~500 MB of JSON output:

| | before | after |
| --- | --- | --- |
| `--format=json` wall clock | 13.3 s | 12.6 s |
| peak RSS | 4668 MB | 3576 MB |

Measured as best-of-3 with the two binaries interleaved, output redirected to `/dev/null`.

## Correctness

Output is byte-identical before and after. Verified on `apps/oxlint/fixtures/cli/output_formatter_diagnostic` and on a 365k-diagnostic subset of vscode (170 MB of JSON compared byte-for-byte). Note that oxlint's diagnostic ordering is nondeterministic run-to-run under parallelism, so the comparison was run with `--threads=1`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
connorshea committed 2026-08-05 09:52:40 +00:00
1 parent 8492cfd085
commit 1cf7ddea46
1 file changed
+9 -10
+9 -10
View File
@@ -139,16 +139,15 @@ impl JsonReporter {
/// <https://github.com/fregante/eslint-formatters/tree/ae1fd9748596447d1fd09625c33d9e7ba9a3d06d/packages/eslint-formatter-json>
fn format_json(diagnostics: &mut Vec<Error>) -> String {
let handler = JSONReportHandler::new();
let messages = diagnostics
.drain(..)
.map(|error| {
let mut output = String::new();
handler.render_report(&mut output, error.as_ref()).unwrap();
output
})
.collect::<Vec<_>>()
.join(",\n");
format!("[{messages}]")
let mut output = String::from("[");
for (index, error) in diagnostics.drain(..).enumerate() {
if index > 0 {
output.push_str(",\n");
}
handler.render_report(&mut output, error.as_ref()).unwrap();
}
output.push(']');
output
}
#[cfg(test)]