fix(client-core): resolve runtimeConfigPath relative to generated output#3770
fix(client-core): resolve runtimeConfigPath relative to generated output#3770inas-sirhan wants to merge 2 commits intohey-api:mainfrom
Conversation
|
|
|
Reviewed PR #3770. The core fix in Task list (5/5 completed)
|
|
@inas-sirhan is attempting to deploy a commit to the Hey API Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: 2efdee9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
TL;DR — When a user sets Key changes
Summary | 116 files | 2 commits | base: Resolve
|
| Input shape | Example | Behavior |
|---|---|---|
./-prefixed (cwd-relative) |
'./src/config.ts' |
Resolved to absolute via process.cwd(), then made relative to output |
| Absolute path | '/home/user/config.ts' |
Made relative to output directly |
| Bare specifier | '../foo', '@scope/pkg' |
Returned unchanged |
Why are
Paths like../-prefixed paths left unchanged?../hey-apiare already relative — they are treated as relative to the output directory in the generated import, which matches user intent. Only./-prefixed paths need transformation because they are naturally interpreted as relative to the project root (where the config file lives), not the output directory.
client.ts · clients.test.ts · my-config.ts
There was a problem hiding this comment.
Important
The resolution logic has an asymmetry that could confuse users, and the JSDoc on runtimeConfigPath is now inaccurate. Worth addressing before merge.
The fix itself is correct — ./-prefixed paths are resolved from cwd and made relative to the output directory, which matches what the docs examples have always shown. Backward compatibility for ../ and bare specifiers is preserved. Snapshot math checks out across all 7 clients.
JSDoc on runtimeConfigPath (types.ts:48): The JSDoc says "Relative path to the runtime configuration file" — this is now inaccurate. After this PR, ./-prefixed paths are resolved from cwd, and absolute paths are also supported. Consider updating to something like: "Path to the runtime configuration file. Paths starting with ./ or absolute paths are resolved relative to cwd and rewritten to be relative to the generated output. Other paths (../foo, @scope/pkg, foo) are used as-is."
Task list (5/5 completed)
- Checkout PR and read diff
- Analyze core logic change in runtimeConfigPath resolution
- Review snapshot/test changes
- Impact analysis: check for stale references or missed call sites
- Self-critique and submit review
| if (!path.isAbsolute(runtimeConfigPath) && !runtimeConfigPath.startsWith('./')) { | ||
| return runtimeConfigPath; |
There was a problem hiding this comment.
The classification heuristic creates an asymmetry that isn't obvious to users:
./src/config.ts→ resolved from cwd, then made relative to output../config.ts→ passed through verbatim (treated as already relative to output)
This means ./ and ../ have fundamentally different semantics even though they're both conventional relative-path prefixes. A user writing runtimeConfigPath: '../shared/config.ts' probably intends it relative to cwd (same as ./), not relative to the output directory.
Consider resolving all dotted relative paths (starting with ./ or ../) from cwd, and only passing through bare specifiers (no leading .). That would make the behavior consistent and match how output.path itself is resolved. The existing openapi-ts-next example ('../hey-api') would need its path updated, but it would behave correctly regardless.
| const absoluteInputPath = path.isAbsolute(runtimeConfigPath) | ||
| ? runtimeConfigPath | ||
| : path.resolve(process.cwd(), runtimeConfigPath); | ||
| const relative = path.relative(outputPath, absoluteInputPath).split(path.sep).join('/'); |
There was a problem hiding this comment.
Normalizing path.sep to / is the right call for generated imports.
Paths starting with './' or absolute paths are now resolved from the current working directory and made relative to the generated output directory, so the resulting import path is correct regardless of where the user's runtime config file lives. Paths without a './' prefix (e.g. '../my-config', 'my-config', '@scope/pkg') are kept as-is to preserve the existing convention of treating them as relative to the generated output or as bare module specifiers. Closes hey-api#3394
f97ee82 to
2efdee9
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3770 +/- ##
==========================================
- Coverage 40.01% 40.00% -0.02%
==========================================
Files 521 521
Lines 19300 19309 +9
Branches 5756 5767 +11
==========================================
+ Hits 7723 7724 +1
- Misses 9374 9379 +5
- Partials 2203 2206 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@hey-api/codegen-core
@hey-api/json-schema-ref-parser
@hey-api/nuxt
@hey-api/openapi-ts
@hey-api/shared
@hey-api/spec-types
@hey-api/types
@hey-api/vite-plugin
commit: |
|
No action needed — the reviewer's comment ( Task list (1/1 completed)
|
|
@inas-sirhan how does it handle absolute paths and relative paths if the config is in a nested folder (i.e., not in root)? Is it the same how |
|
same as
for consistency i checked output.path = path.resolve(process.cwd(), output.path);so if someone's config is in |

Fixes #3394
The docs show
runtimeConfigPath: './src/hey-api.ts', but this was being copied verbatim into the generated file, so the import ended up wrong unless the user manually wrote the path relative to the generated output directory.Paths starting with
./or absolute paths are now resolved from cwd, then made relative to the generated output directory. Bare specifiers (../foo,foo,@scope/pkg) are kept as-is to preserve the current convention and support package imports.Examples:
Added a
runtime-config-pathscenario to the client snapshot tests across all 7 HTTP clients (angular, axios, fetch, ky, next, nuxt, ofetch).