Skip to content

feat: add support for AsyncAPI 2 and 3 in the split command#2552

Open
tibisabau wants to merge 4 commits intoRedocly:mainfrom
tibisabau:feat/add-support-asyncapi23-split
Open

feat: add support for AsyncAPI 2 and 3 in the split command#2552
tibisabau wants to merge 4 commits intoRedocly:mainfrom
tibisabau:feat/add-support-asyncapi23-split

Conversation

@tibisabau
Copy link
Contributor

What/Why/How?

What: Added support for AsyncAPI 2.x and 3.x specifications to the split command, which previously only supported OpenAPI 3.x.

Why: To enable users to split AsyncAPI definition files into modular directory structures, similar to the existing OpenAPI functionality. This addresses issue #2352.

How:

  • Extended type definitions to include AsyncAPI 2 and 3 component names (schemas, messages, parameters, channels, operations, etc.)
  • Implemented splitAsyncApiDefinition() orchestrator function to handle both AsyncAPI versions
  • Added iterateAsyncApiChannels() to split channels into separate files with proper $ref replacements
  • Implemented iterateAsyncApiOperations() for AsyncAPI 3 operations splitting
  • Created iterateAsyncApiComponents() to handle component extraction with version-specific logic
  • Enhanced spec detection in validateDefinitionFileName() to recognize AsyncAPI documents

Reference

Resolves #2352

Testing

  • Created test fixtures: tests/e2e/split/asyncapi2-basic/asyncapi.yaml and tests/e2e/split/asyncapi3-basic/asyncapi.yaml
  • Ran unit test suite
  • Manual verification: Successfully split both AsyncAPI 2 and 3 documents into proper directory structures with correct $ref resolution
  • TypeScript compilation passed with no errors
  • Code formatted with Prettier

Screenshots (optional)

N/A - CLI functionality

Check yourself

  • Code changed? - Tested with Redoc/Realm/Reunite (internal)
  • All new/updated code is covered by tests
  • New package installed? - Tested in different environments (browser/node)
  • Documentation update considered

Security

  • The security impact of the change has been considered
  • Code follows company security practices and guidelines

@tibisabau tibisabau requested review from a team as code owners February 10, 2026 15:09
@changeset-bot
Copy link

changeset-bot bot commented Feb 10, 2026

🦋 Changeset detected

Latest commit: d2699f3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/cli Major
@redocly/openapi-core Major
@redocly/respect-core Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

splitDefinition(openapi, outDir, separator, ext);
const definition = readYaml(api) as AnyDefinition;

const specType = validateDefinitionFileName(api, definition);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like returning specType from validateDefinitionFileName breaks single responsibility principle.
Could you please do detect spec separately from validation.

collectSpecData?.(definition);

if (specType === 'openapi') {
splitDefinition(definition as AnyOas3Definition, outDir, separator, ext);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets rename it to splitOASDefinition.

const openapi = readYaml(api) as AnyOas3Definition;
collectSpecData?.(openapi);
splitDefinition(openapi, outDir, separator, ext);
const definition = readYaml(api) as AnyDefinition;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we also checked that file exist before readYaml before the change inside
validateDefinitionFileName.

}

function validateDefinitionFileName(fileName: string) {
function validateDefinitionFileName(fileName: string, file?: Definition): 'openapi' | 'asyncapi' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s not immediately clear why the validate function returns the equivalent of detectSpec.

fs.mkdirSync(asyncapiDir, { recursive: true });

const componentsFiles: ComponentsFiles = {};
const detectedVersion = detectSpec(asyncapi);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you already called detectSpec previously in the flow, could you please check if it make sense to pass the result as parameter?

iterateAsyncApiComponents(asyncapi, asyncapiDir, componentsFiles, ext, specVersion);

// Split channels
if ((asyncapi as any).channels) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this type cast is necessary?
Both v2 and v3 AsyncAPI can have channels.

function findAsyncApiComponentTypes(components: any, specVersion: 'async2' | 'async3') {
const componentNames =
specVersion === 'async2' ? ASYNCAPI2_COMPONENT_NAMES : ASYNCAPI3_COMPONENT_NAMES;
return componentNames.filter(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider make it more readable, e.g. =>

const excluded = new Set([
  'securitySchemes',
  'servers',
  'serverVariables',
  'channels',
  'operations',
]);

return componentNames.filter(
  (item) => !excluded.has(item) && item in components
);


const componentsFiles: ComponentsFiles = {};
const detectedVersion = detectSpec(asyncapi);
const specVersion: 'async2' | 'async3' = detectedVersion === 'async2' ? 'async2' : 'async3';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const specVersion: 'async2' | 'async3' = detectedVersion === 'async2' ? 'async2' : 'async3';
const specVersion: 'async2' | 'async3' = detectedVersion;

"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"dev": true,
"license": "MIT",
"peer": true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see that some packages were added.
Could you please rebase changes from main.
Maybe you are using different npm version, could you please try npm install with 11.10.1.

@@ -0,0 +1,33 @@
asyncapi: '2.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see that e2e AsyncAPI examples were added, but I don’t see any snapshots or usage of those two descriptions.
Maybe some related changes were not pushed?

@@ -0,0 +1,39 @@
asyncapi: 3.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see that e2e AsyncAPI examples were added, but I don’t see any snapshots or usage of those two descriptions.
Maybe some related changes were not pushed?

info:
title: Simple AsyncAPI Example
version: '1.0.0'
description: A simple AsyncAPI example for testing split command
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: A simple AsyncAPI example for testing split command
description: A simple AsyncAPI v2 example for testing split command

@tibisabau tibisabau force-pushed the feat/add-support-asyncapi23-split branch from e9121a4 to 8875719 Compare March 13, 2026 19:14
@tibisabau tibisabau changed the title feat: Add support for AsyncAPI 2 and 3 in the split command feat: add support for AsyncAPI 2 and 3 in the split command Mar 13, 2026
@tibisabau tibisabau requested a review from DmitryAnansky March 13, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support AsyncAPI 3 (and if possible 2) in the split command

2 participants