Skip to content

fix: resolve external $ref files relative to spec file location#2056

Closed
chengyixu wants to merge 2 commits intoasyncapi:masterfrom
chengyixu:fix/external-ref-resolution
Closed

fix: resolve external $ref files relative to spec file location#2056
chengyixu wants to merge 2 commits intoasyncapi:masterfrom
chengyixu:fix/external-ref-resolution

Conversation

@chengyixu
Copy link

Summary

Fixes #1839 — External $ref files in the same directory are not resolved since the CLI architecture refactoring.

Root Cause

When the CLI was refactored to use GeneratorService, the path option passed to generator.generateFromString() was changed from a string file path to a Specification object:

// Before (working - from commit c1e1b39):
await generator.generateFromString(specification.text(), {...genOption, path: asyncapi});
// `asyncapi` was a string like "./src/contract/asyncapi.yaml"

// After (broken - current code):
await generator.generateFromString(asyncapi.text(), {
  ...genOption,
  path: asyncapi,  // ← Specification object, not a string!
});

The @asyncapi/generator's parser calls convertOldOptionsToNew() which checks typeof oldOptions.path === 'string' to set the source path for resolving relative $ref references. Since a Specification object is not a string, the source path was never set, causing the @asyncapi/parser (and downstream @stoplight/json-ref-readers) to resolve relative paths against the CWD instead of the spec file's directory.

Fix

Use asyncapi.getSource() which returns the file path string (or URL) from the Specification object:

await generator.generateFromString(asyncapi.text(), {
  ...genOption,
  path: asyncapi.getSource(),  // ← Returns string file path or URL
});

Also updated the GeneratorRunOptions interface to correctly type path as string instead of Specification.

Changes

  • src/domains/services/generator.service.ts: Pass asyncapi.getSource() instead of the Specification object as path; fix GeneratorRunOptions.path type from Specification to string
  • test/integration/generate/fromTemplate.test.ts: Add integration test for external $ref resolution from a subdirectory
  • test/unit/services/generator.service.test.ts: Add unit test verifying Specification.getSource() returns a string path

Test plan

  • Existing integration tests pass (no regressions)
  • New test: generate from template with external $ref in subdirectory (./test/fixtures/external-refs/main.yaml)
  • Manual test: create an AsyncAPI spec in a subdirectory referencing other YAML files via $ref and run asyncapi generate fromTemplate

🤖 Generated with Claude Code

…capi#1839)

When the CLI architecture was refactored to use GeneratorService, the
`path` option passed to `generator.generateFromString()` was changed
from a string file path to a Specification object. The generator's
parser checks `typeof oldOptions.path === 'string'` to set the source
path for resolving relative $ref references. Since a Specification
object is not a string, the source path was never set, causing
external file references to fail when the spec is in a subdirectory.

The fix uses `asyncapi.getSource()` which returns the file path string
(or URL) from the Specification object, restoring correct $ref
resolution behavior.

Closes asyncapi#1839

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: d4e1d37

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

This PR includes changesets to release 1 package
Name Type
@asyncapi/cli Patch

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link

@chengyixu
Copy link
Author

Hi @AayushSaini101 @Shurtu-gal! Pinging for review on this PR.

Compared to the other fix for the same issue (#2046, opened a day earlier), this PR includes:

  • Integration test: adds a real fixture file (test/fixtures/external-refs/main.yaml) and tests the generate command end-to-end with external $ref resolution from a subdirectory
  • Unit test: verifies Specification.getSource() returns a string path
  • Type fix: corrects GeneratorRunOptions.path type from Specification to string

All CI checks are green (SonarCloud Quality Gate passed, Lint PR title passed). Happy to address any feedback!

@chengyixu
Copy link
Author

Hi @asyncapi/cli-maintainers! This PR fixes external $ref resolution relative to spec file location. All CI checks are passing. Happy to adjust anything based on your feedback!

@chengyixu
Copy link
Author

Hi! Just a friendly check-in on this resolution fix — CI is still passing. Happy to rebase or address any feedback for merge. Thanks!

@chengyixu
Copy link
Author

Hi @asyncapi/cli-maintainers! This PR has been open since 2026-03-18 and all CI checks are passing. It fixes external $ref resolution relative to the spec file location. Competitive context: there's another open PR (#2046) for the same issue. I'd appreciate a review to move this forward. Thank you!

@chengyixu
Copy link
Author

Hi @asyncapi/cli-maintainers! Following up on this external $ref fix — resolves file path resolution relative to spec file location (issue #1839, part of bounty program 2026-04). This PR includes integration tests with real fixture files and a unit test, making it more comprehensive than the competing PR. All CI checks passing, SonarCloud green. Would appreciate a review to settle which PR addresses this bounty issue. Thanks!

@chengyixu
Copy link
Author

Hi @asyncapi/cli-maintainers! PR #2056 fixes the external $ref resolution regression (issue #1839, part of the 2026-04 bounty program). All CI checks passing — would appreciate a review when you have a chance. Happy to adjust anything needed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[BUG] external files in same directory are not resolved via $ref anymore, since v3.3.0

2 participants