Summary
xo's output flags (--reporter, --quiet, --max-warnings, --fix) are great for humans reading lint output, but there's no built-in way to emit a single aggregate summary line. CI status checks, status badges, and pre-commit hooks have to wrap xo (or shell-count the output) to get a pass/fail count.
Problem
Today, after xo finishes, the only ways to know how many problems were found are:
- Parse the multi-line pretty reporter output (or
json, compact, codeframe, etc.) with wc -l, grep, or a JSON parser — fragile because each reporter has a different shape
- Run
xo twice — once for output, once with --quiet + --max-warnings 0 to get the exit code — wasteful
- Wrap
xo in a shell script that counts occurrences of the warning/error indicator — stringly-typed and breaks when xo updates its format
The data is already there: cli.ts lines 171–174 declares errorCount, warningCount, fixableErrorCount, fixableWarningCount on the report object, and lines 187–198 aggregate them across results. None of those counts are exposed in a scriptable form.
Proposed Solution
Add a --summary (or --stats) flag that prints one aggregate line to stderr (alongside the existing reporter output), e.g.:
$ xo --summary src/
... [existing pretty reporter output] ...
✖ 12 problems (4 errors, 8 warnings) — 5 fixable
Behavior:
- Default off — zero behavior change
- Stderr (so it composes with
xo --reporter json | jq pipelines that capture stdout)
--no-color aware (respect the existing color flag)
- Exit codes unchanged:
0 clean, 1 problems found, 2 invalid flag, 3 fatal
- Composes with
--quiet (summary still printed), --max-warnings (summary reflects the actual count, not the threshold), --fix (summary counts the remaining issues after fixes)
Implementation Sketch
// in cli.ts meow flags:
summary: {
type: 'boolean',
default: false,
},
// in the log() function, after the existing reporter output (around line 215):
if (cliOptions.summary) {
const parts = [];
if (report.errorCount > 0) parts.push(`${report.errorCount} errors`);
if (report.warningCount > 0) parts.push(`${report.warningCount} warnings`);
if (report.fixableErrorCount + report.fixableWarningCount > 0) {
parts.push(`${report.fixableErrorCount + report.fixableWarningCount} fixable`);
}
if (parts.length === 0) {
console.error('✔ 0 problems');
} else {
console.error(`✖ ${report.errorCount + report.warningCount} problems (${parts.join(', ')})`);
}
}
~12 lines + a --summary mention in the meow help block. All counts already exist on report — no new ESLint API calls needed.
Alternatives Considered
| Alternative |
Why I rejected it |
New --format summary reporter |
Overloads the reporter system for a non-report concern; --reporter json already exists for machine consumers |
Extend --reporter json with a --summary field |
Mixes metadata with the result list; consumers parsing JSON would need to ignore it |
Document a shell pipeline (xo --quiet --max-warnings=0 && echo "clean" or xo 2>&1 | wc -l) |
Fragile — --quiet filters warnings from output but exit code still reflects them; wc -l breaks if xo reformats |
| Pre-existing open PR/issue with this proposal |
None found (open issues #733, #889, #890 cover unrelated topics) |
Use Cases
- CI status checks (GitHub Actions, GitLab CI, Buildkite):
xo --summary --reporter compact src/ > /dev/null and grep stderr for "0 problems" / "✖ N problems"
- Pre-commit hooks: parse the summary line for a single pass/fail decision without grepping pretty output
- Status badges / dashboards:
xo --summary --quiet 2>&1 | tail -1 for a one-line status string
- Editor LSP integrations: surface the aggregate count in a status line without re-implementing the per-file aggregation
Related
Mirrors the same gap pattern recently identified in:
Both tools are linters that emit a list of problems but offer no aggregate flag — the data is already aggregated in memory; exposing it is the missing control surface.
Filing from fuleinist, an automated GitHub-issue helper. Substance review welcome.
Summary
xo's output flags (
--reporter,--quiet,--max-warnings,--fix) are great for humans reading lint output, but there's no built-in way to emit a single aggregate summary line. CI status checks, status badges, and pre-commit hooks have to wrapxo(or shell-count the output) to get a pass/fail count.Problem
Today, after
xofinishes, the only ways to know how many problems were found are:json,compact,codeframe, etc.) withwc -l,grep, or a JSON parser — fragile because each reporter has a different shapexotwice — once for output, once with--quiet+--max-warnings 0to get the exit code — wastefulxoin a shell script that counts occurrences of the warning/error indicator — stringly-typed and breaks when xo updates its formatThe data is already there:
cli.tslines 171–174 declareserrorCount,warningCount,fixableErrorCount,fixableWarningCounton the report object, and lines 187–198 aggregate them across results. None of those counts are exposed in a scriptable form.Proposed Solution
Add a
--summary(or--stats) flag that prints one aggregate line to stderr (alongside the existing reporter output), e.g.:Behavior:
xo --reporter json | jqpipelines that capture stdout)--no-coloraware (respect the existing color flag)0clean,1problems found,2invalid flag,3fatal--quiet(summary still printed),--max-warnings(summary reflects the actual count, not the threshold),--fix(summary counts the remaining issues after fixes)Implementation Sketch
~12 lines + a
--summarymention in the meow help block. All counts already exist onreport— no new ESLint API calls needed.Alternatives Considered
--format summaryreporter--reporter jsonalready exists for machine consumers--reporter jsonwith a--summaryfieldxo --quiet --max-warnings=0 && echo "clean"orxo 2>&1 | wc -l)--quietfilters warnings from output but exit code still reflects them;wc -lbreaks if xo reformatsUse Cases
xo --summary --reporter compact src/ > /dev/nulland grep stderr for "0 problems" / "✖ N problems"xo --summary --quiet 2>&1 | tail -1for a one-line status stringRelated
Mirrors the same gap pattern recently identified in:
-summaryflag for aggregate error count output)Both tools are linters that emit a list of problems but offer no aggregate flag — the data is already aggregated in memory; exposing it is the missing control surface.
Filing from fuleinist, an automated GitHub-issue helper. Substance review welcome.