Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
974233d
feat: add support for vendor extensions in stats reporting
n0rahh Aug 5, 2026
9a79e40
chore: update stats documentation to include Vendor Extensions metrics
n0rahh Aug 5, 2026
b957cfe
chore: update snapshots
n0rahh Aug 5, 2026
304374f
tests: add e2e tests
n0rahh Aug 5, 2026
5af764e
tests: add unit tests
n0rahh Aug 5, 2026
d8f062b
chore: update snapshot to include Vendor Extensions in stats
n0rahh Aug 5, 2026
3f2b9f8
feat: add Vendor Extensions metric to stats command
n0rahh Aug 5, 2026
2efddb1
feat: enhance StatsSpecExtensions to correctly handle extensions next…
n0rahh Aug 5, 2026
c2439e9
Update .changeset/seven-waves-create.md
JLekawa Aug 5, 2026
05fbcdf
feat: add support for counting map-typed extensions in StatsSpecExten…
n0rahh Aug 5, 2026
15e669c
feat: add masking for sensitive values in StatsSpecExtensions
n0rahh Aug 5, 2026
c99afa0
feat: add authorization key to be masked in StatsSpecExtensions tests
n0rahh Aug 5, 2026
3bb9922
chore: refactor after cr
n0rahh Aug 6, 2026
d327074
Merge branch 'main' into feat/stats-for-vendor-extensions
n0rahh Aug 6, 2026
13e252e
feat: add support for collecting sibling extensions in stats processing
n0rahh Aug 6, 2026
d1430fd
chore: update docs examples
n0rahh Aug 6, 2026
a7053a7
feat: enhance stats processing for vendor extensions with detailed co…
n0rahh Aug 7, 2026
a68162f
feat: implement spec extension dispatch and enhance stats collection …
n0rahh Aug 7, 2026
561ede2
feat: add tests and fixtures for vendor extension counts in AsyncAPI …
n0rahh Aug 7, 2026
06d4e23
feat: update stats processing to correctly count 'x-query' extensions…
n0rahh Aug 7, 2026
280804f
feat: standardize indentation for vendor extensions in stats output
n0rahh Aug 10, 2026
ef28db3
feat: fix stats command to accurately report parameters for AsyncAPI …
n0rahh Aug 10, 2026
bbedead
feat: enhance stats output for vendor extensions by adding new extens…
n0rahh Aug 11, 2026
66b983c
chore: update changeset
n0rahh Aug 11, 2026
9ef37bd
Merge branch 'main' into feat/stats-for-vendor-extensions
n0rahh Aug 12, 2026
141c77c
feat: add tests for ensureSpecExtensionDispatch functionality
n0rahh Aug 12, 2026
c97e6fb
chore: enhance vendor extension handling and statistics collection
n0rahh Aug 13, 2026
34f0c03
feat: enhance spec extension handling in walkDocument function
n0rahh Aug 13, 2026
33e26b1
feat: enhance SpecExtension lifecycle handling in tests and walk func…
n0rahh Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/olive-donkeys-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@redocly/openapi-core': patch
'@redocly/cli': patch
---

Fixed the `stats` command reporting wrong parameter count for AsyncAPI descriptions.
6 changes: 6 additions & 0 deletions .changeset/seven-waves-create.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@redocly/openapi-core': minor
'@redocly/cli': minor
---

Added a Vendor Extensions metric to the `stats` command that reports how many distinct `x-` extensions a description file uses and how often each one occurs.
41 changes: 41 additions & 0 deletions docs/@v2/commands/stats.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The metrics reported depend on the type of API description:
- Webhooks
- Operations
- Tags
- Vendor Extensions

**AsyncAPI 2.x and AsyncAPI 3.x**

Expand All @@ -31,6 +32,9 @@ The metrics reported depend on the type of API description:
- Channels
- Operations
- Tags
- Vendor Extensions

For **Vendor Extensions**, the count is the number of distinct `x-` extensions used, and each extension is listed with how many times it occurs.

If you're interested in the technical details, the statistics are calculated using the counting logic from the `StatsVisitor` module.

Expand Down Expand Up @@ -123,6 +127,11 @@ Document: museum.yaml stats:
🎣 Webhooks: 0
👷 Operations: 8
🔖 Tags: 3
🧩 Vendor Extensions: 4
- x-badges: 1
- x-codeSamples: 2
- x-internal: 2
- x-metadata: 1

museum.yaml: stats processed in 4ms
</pre>
Expand All @@ -139,6 +148,9 @@ Document: asyncapi.yaml stats:
📡 Channels: 1
👷 Operations: 1
🔖 Tags: 2
🧩 Vendor Extensions: 2
- x-internal: 1
- x-metadata: 1

asyncapi.yaml: stats processed in 4ms
</pre>
Expand Down Expand Up @@ -187,6 +199,16 @@ The following is an example JSON output for an OpenAPI description:
"tags": {
"metric": "🔖 Tags",
"total": 3
},
"xExtensions": {
"metric": "🧩 Vendor Extensions",
"total": 4,
"counts": {
"x-badges": 1,
"x-codeSamples": 2,
"x-internal": 2,
"x-metadata": 1
}
}
}
</pre>
Expand Down Expand Up @@ -214,6 +236,15 @@ The following is an example source output for an OpenAPI description:
| 🎣 Webhooks | 0 |
| 👷 Operations | 8 |
| 🔖 Tags | 3 |
| 🧩 Vendor Extensions | 4 |

#### 🧩 Vendor Extensions
| Extension | Count |
| --- | --- |
| x-badges | 1 |
| x-codeSamples | 2 |
| x-internal | 2 |
| x-metadata | 1 |

</pre>

Expand All @@ -230,6 +261,16 @@ Here's the rendered example source output:
| 🎣 Webhooks | 0 |
| 👷 Operations | 8 |
| 🔖 Tags | 3 |
| 🧩 Vendor Extensions | 4 |

**🧩 Vendor Extensions**

| Extension | Count |
| ------------- | ----- |
| x-badges | 1 |
| x-codeSamples | 2 |
| x-internal | 2 |
| x-metadata | 1 |

For AsyncAPI descriptions, the table includes a `📡 Channels` row instead of the `🔗 Links`, `🔀 Path Items`, and `🎣 Webhooks` rows.

Expand Down
14 changes: 6 additions & 8 deletions packages/cli/src/commands/stats/print-stats/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import {
} from '@redocly/openapi-core';

export function printStatsJson(statsAccumulator: OASStatsAccumulator | AsyncAPIStatsAccumulator) {
const json: any = {};
for (const key of Object.keys(statsAccumulator)) {
const stat = statsAccumulator[key as keyof typeof statsAccumulator];
json[key] = {
metric: stat.metric,
total: stat.total,
};
}
const json = Object.fromEntries(
Object.entries(statsAccumulator).map(([key, { metric, total, counts }]) => [
key,
{ metric, total, counts },
])
);

logger.output(JSON.stringify(json, null, 2));
}
16 changes: 12 additions & 4 deletions packages/cli/src/commands/stats/print-stats/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ export function printStatsMarkdown(
statsAccumulator: OASStatsAccumulator | AsyncAPIStatsAccumulator
) {
let output = '| Feature | Count |\n| --- | --- |\n';
for (const key of Object.keys(statsAccumulator)) {
const stat = statsAccumulator[key as keyof typeof statsAccumulator];
output += '| ' + stat.metric + ' | ' + stat.total + ' |\n';
const breakdowns: string[] = [];
for (const { metric, total, counts } of Object.values(statsAccumulator)) {
output += `| ${metric} | ${total} |\n`;
const countEntries = Object.entries(counts ?? {});
if (countEntries.length) {
breakdowns.push(
`\n#### ${metric}\n| Extension | Count |\n| --- | --- |\n` +
countEntries.map(([name, count]) => `| ${name} | ${count} |`).join('\n') +
'\n'
);
}
}

logger.output(output);
logger.output(output + breakdowns.join(''));
}
9 changes: 5 additions & 4 deletions packages/cli/src/commands/stats/print-stats/stylish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import * as colors from 'colorette';
export function printStatsStylish(
statsAccumulator: OASStatsAccumulator | AsyncAPIStatsAccumulator
) {
for (const node in statsAccumulator) {
const stat = statsAccumulator[node as keyof typeof statsAccumulator];
const { metric, total, color } = stat;
const colorFn = colors[color as keyof typeof colors] as (text: string) => string;
for (const { metric, total, color, counts } of Object.values(statsAccumulator)) {
const colorFn = colors[color];
logger.output(colorFn(`${metric}: ${total} \n`));
for (const [name, count] of Object.entries(counts ?? {})) {
logger.output(colorFn(` - ${name}: ${count} \n`));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function resolveStatsVisitorAndAccumulator(specVersion: SpecVersion) {
webhooks: { metric: '🎣 Webhooks', total: 0, color: 'green' },
operations: { metric: '👷 Operations', total: 0, color: 'yellow' },
tags: { metric: '🔖 Tags', total: 0, color: 'white', items: new Set() },
xExtensions: { metric: '🧩 Vendor Extensions', total: 0, color: 'cyan', counts: {} },
};
const statsAccumulatorAsync: AsyncAPIStatsAccumulator = {
refs: { metric: '🚗 References', total: 0, color: 'red', items: new Set() },
Expand All @@ -29,6 +30,7 @@ export function resolveStatsVisitorAndAccumulator(specVersion: SpecVersion) {
channels: { metric: '📡 Channels', total: 0, color: 'green' },
operations: { metric: '👷 Operations', total: 0, color: 'yellow' },
tags: { metric: '🔖 Tags', total: 0, color: 'white', items: new Set() },
xExtensions: { metric: '🧩 Vendor Extensions', total: 0, color: 'cyan', counts: {} },
};

let statsVisitor, statsAccumulator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,7 @@ exports[`createConfigTypes > matches snapshot for the default config schema 1`]
"NamedParameters",
"NamedSecuritySchemes",
"SecurityScheme",
"Scopes",
"XCodeSample",
"XCodeSampleList",
"XServerList",
Expand Down
Loading
Loading