Skip to content

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

Open
tibisabau wants to merge 8 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 8 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: 3205cd1

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 Minor
@redocly/openapi-core Minor
@redocly/respect-core Minor

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

@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
@DmitryAnansky
Copy link
Contributor

@tibisabau
Could you please consider adding happy-path unit tests for the newly added functions?
Alternatively, we could loosen the test coverage requirements for now.

@tibisabau tibisabau requested a review from DmitryAnansky March 23, 2026 19:19
tibisabau and others added 2 commits March 24, 2026 07:58
@tibisabau tibisabau requested a review from DmitryAnansky March 24, 2026 07:59
}
}

function removeAsyncApiEmptyComponents(
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this one can be simplified:

function removeAsyncApiEmptyComponents(
  asyncapi: AnyAsyncApiDefinition,
  componentType: AsyncApi2Component | AsyncApi3Component
) {
  const components = (asyncapi as any).components;
  if (!components) return;

  if (isEmptyObject(components[componentType])) {
    delete components[componentType];
  }

  if (isEmptyObject(components)) {
    delete (asyncapi as any).components;
  }
}

function findAsyncApiComponentTypes(components: any, specVersion: 'async2' | 'async3') {
const componentNames =
specVersion === 'async2' ? ASYNCAPI2_COMPONENT_NAMES : ASYNCAPI3_COMPONENT_NAMES;
const excluded = new Set([
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need this exclude?
Will it make sense to remove items you want to exclude from this place
https://github.com/Redocly/redocly-cli/pull/2552/changes#diff-8200bdf7c09b5fccef9dca77890af1ed6ec7bd1332d08aeef1c1d846e296f18dR79

and check if they are in components?

return parseYaml(fs.readFileSync(fileName, 'utf8')) as Definition;
} catch (e) {
return exitWithError(e.message);
function detectSpecType(definition: Definition): 'openapi' | 'asyncapi' | null {
Copy link
Contributor

@DmitryAnansky DmitryAnansky Mar 25, 2026

Choose a reason for hiding this comment

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

Do we need this detectSpecType function.
Maybe we can just use already detected spec version and build switch case logic, similar to this example

  const specVersion = detectSpec(definition) 

  switch (specVersion) {
    case 'async2':
....
      break;
    case 'async3':
....
      break;
    case 'oas2':
    case 'oas3_0':
    case 'oas3_1':
    case 'oas3_2':
....
      break;
    default:
....
  }

@DmitryAnansky
Copy link
Contributor

@tibisabau
Thanks for adding the e2e examples — they look great!
Could you please add one more e2e example with a more complex structure to help verify that it works well with more advanced specs?

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

3 participants