Skip to content

Commit e4eea23

Browse files
committed
fix: add output.module option
1 parent 67351ad commit e4eea23

21 files changed

Lines changed: 198 additions & 213 deletions

File tree

.changeset/tangy-cities-carry.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@hey-api/openapi-ts": patch
3+
"@hey-api/shared": patch
4+
---
5+
6+
**output**: add `module` option

docs/openapi-ts/clients/ofetch.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ Interceptors (middleware) can be used to modify requests before they're sent or
144144
The `ofetch` client supports two complementary options:
145145

146146
- built-in Hey API interceptors exposed via `client.interceptors`
147-
- native `ofetch` hooks passed through config (e.g. `onRequest`)
147+
- native `ofetch` hooks passed through config (e.g., `onRequest`)
148148

149149
### Example: Request interceptor
150150

docs/openapi-ts/configuration/output.md

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ export default {
3636

3737
You can learn more about complex use cases in the [Advanced](/openapi-ts/configuration#advanced) section.
3838

39-
## File Name
39+
## File
40+
41+
Control how files are named and annotated in the generated output.
42+
43+
### File Name
4044

4145
You can customize the naming and casing pattern for files using the `fileName` option.
4246

@@ -108,66 +112,95 @@ export default {
108112

109113
:::
110114

111-
## Module Extension
115+
### File Header
112116

113-
You can customize the extension used for TypeScript modules.
117+
The generated output includes a notice in every file warning that any modifications will be lost when the files are regenerated. You can customize or disable this notice using the `header` option.
114118

115119
::: code-group
116120

117-
```js [default]
118-
export default {
119-
input: 'hey-api/backend', // sign up at app.heyapi.dev
120-
output: {
121-
importFileExtension: undefined, // [!code ++]
122-
path: 'src/client',
123-
},
124-
};
121+
```js [example]
122+
/* eslint-disable */
123+
// This file is auto-generated by @hey-api/openapi-ts
124+
125+
/** ... */
125126
```
126127

127-
```js [disabled]
128+
<!-- prettier-ignore-start -->
129+
```js [config]
128130
export default {
129131
input: 'hey-api/backend', // sign up at app.heyapi.dev
130132
output: {
131-
importFileExtension: null, // [!code ++]
133+
header: (ctx) => [ // [!code ++]
134+
'/* eslint-disable */', // [!code ++]
135+
...ctx.defaultValue, // [!code ++]
136+
], // [!code ++]
132137
path: 'src/client',
133138
},
134139
};
135140
```
141+
<!-- prettier-ignore-end -->
142+
143+
:::
144+
145+
## Module
146+
147+
Control how module specifiers are generated in the output.
148+
149+
### Module Extension
150+
151+
Set `module.extension` to define the file extension used in import specifiers. This is useful when targeting environments that require fully specified imports (e.g., Node ESM or certain bundlers).
152+
153+
::: code-group
154+
155+
```js [example]
156+
import foo from './foo.js';
157+
import bar from './bar.js';
158+
```
136159

137-
```js [js]
160+
```js [config]
138161
export default {
139162
input: 'hey-api/backend', // sign up at app.heyapi.dev
140163
output: {
141-
importFileExtension: '.js', // [!code ++]
164+
module: {
165+
extension: '.js', // [!code ++]
166+
},
142167
path: 'src/client',
143168
},
144169
};
145170
```
146171

147-
```js [ts]
172+
:::
173+
174+
### Module Path
175+
176+
Use `module.resolve` for full control over how module specifiers are generated. This lets you override specific modules or redirect them to custom locations (e.g., CDNs or internal aliases).
177+
178+
::: code-group
179+
180+
```js [example]
181+
import * as z from 'https://esm.sh/zod';
182+
```
183+
184+
<!-- prettier-ignore-start -->
185+
```js [config]
148186
export default {
149187
input: 'hey-api/backend', // sign up at app.heyapi.dev
150188
output: {
151-
importFileExtension: '.ts', // [!code ++]
189+
module: {
190+
resolve(path) { // [!code ++]
191+
if (path === 'zod') { // [!code ++]
192+
return 'https://esm.sh/zod'; // [!code ++]
193+
} // [!code ++]
194+
}, // [!code ++]
195+
},
152196
path: 'src/client',
153197
},
154198
};
155199
```
200+
<!-- prettier-ignore-end -->
156201

157202
:::
158203

159-
By default, we don't add a file extension and let the runtime resolve it.
160-
161-
```js
162-
import foo from './foo';
163-
```
164-
165-
If we detect a [TSConfig file](#tsconfig-path) with `moduleResolution` option set to `nodenext`, we default the extension to `.js`.
166-
167-
```js
168-
import foo from './foo.js';
169-
```
170-
171204
## Source
172205

173206
Source is a copy of the input specification used to generate your output. It can be used to power documentation tools or to persist a stable snapshot alongside your generated files.
@@ -337,36 +370,6 @@ export type ChatCompletion_N2 = number;
337370

338371
:::
339372

340-
## File Header
341-
342-
The generated output includes a notice in every file warning that any modifications will be lost when the files are regenerated. You can customize or disable this notice using the `header` option.
343-
344-
::: code-group
345-
346-
<!-- prettier-ignore-start -->
347-
```js [config]
348-
export default {
349-
input: 'hey-api/backend', // sign up at app.heyapi.dev
350-
output: {
351-
header: [
352-
'/* eslint-disable */', // [!code ++]
353-
'// This file is auto-generated by @hey-api/openapi-ts', // [!code ++]
354-
],
355-
path: 'src/client',
356-
},
357-
};
358-
```
359-
<!-- prettier-ignore-end -->
360-
361-
```ts [example]
362-
/* eslint-disable */
363-
// This file is auto-generated by @hey-api/openapi-ts
364-
365-
/** ... */
366-
```
367-
368-
:::
369-
370373
## TSConfig Path
371374

372375
We use the [TSConfig file](https://www.typescriptlang.org/tsconfig/) to generate output matching your project's settings. By default, we attempt to find a TSConfig file starting from the location of the `@hey-api/openapi-ts` configuration file and traversing up.

docs/openapi-ts/migrating.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ If you need to access individual fields, you can do so using the [`.shape`](http
422422
423423
### Bundle `@hey-api/client-*` plugins
424424
425-
In previous releases, you had to install a separate client package to generate a fully working output, e.g. `npm install @hey-api/client-fetch`. This created a few challenges: getting started was slower, upgrading was sometimes painful, and bundling too. Beginning with v0.73.0, all Hey API clients are bundled by default and don't require installing any additional dependencies. You can remove any installed client packages and re-run `@hey-api/openapi-ts`.
425+
In previous releases, you had to install a separate client package to generate a fully working output, e.g., `npm install @hey-api/client-fetch`. This created a few challenges: getting started was slower, upgrading was sometimes painful, and bundling too. Beginning with v0.73.0, all Hey API clients are bundled by default and don't require installing any additional dependencies. You can remove any installed client packages and re-run `@hey-api/openapi-ts`.
426426
427427
```sh
428428
npm uninstall @hey-api/client-fetch

docs/openapi-ts/plugins/concepts/resolvers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export const vAmount = v.number();
130130

131131
### Replace default base
132132

133-
You might want to replace the default base schema, e.g. `v.object()`.
133+
You might want to replace the default base schema, e.g., `v.object()`.
134134

135135
```js
136136
export const vUser = v.object({

docs/openapi-ts/plugins/pinia-colada.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ The Pinia Colada plugin will generate the following artifacts, depending on the
6060

6161
## Queries
6262

63-
Queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Query`, e.g. `getPetByIdQuery()`.
63+
Queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Query`, e.g., `getPetByIdQuery()`.
6464

6565
::: code-group
6666

@@ -191,7 +191,7 @@ export default {
191191

192192
:::
193193

194-
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g. `getPetByIdQueryKey()`.
194+
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g., `getPetByIdQueryKey()`.
195195

196196
::: code-group
197197

@@ -223,7 +223,7 @@ You can customize the naming and casing pattern for `queryKeys` functions using
223223

224224
## Mutations
225225

226-
Mutations are generated from [mutation operations](/openapi-ts/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g. `addPetMutation()`.
226+
Mutations are generated from [mutation operations](/openapi-ts/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g., `addPetMutation()`.
227227

228228
::: code-group
229229

docs/openapi-ts/plugins/tanstack-query.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ The TanStack Query plugin will generate the following artifacts, depending on th
115115

116116
## Queries
117117

118-
Queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Options`, e.g. `getPetByIdOptions()`.
118+
Queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Options`, e.g., `getPetByIdOptions()`.
119119

120120
::: code-group
121121

@@ -281,7 +281,7 @@ export default {
281281

282282
:::
283283

284-
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g. `getPetByIdQueryKey()`.
284+
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g., `getPetByIdQueryKey()`.
285285

286286
::: code-group
287287

@@ -313,7 +313,7 @@ You can customize the naming and casing pattern for `queryKeys` functions using
313313

314314
## Infinite Queries
315315

316-
Infinite queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations) if we detect a [pagination](/openapi-ts/configuration/parser#pagination) parameter. The generated infinite query functions follow the naming convention of SDK functions and by default append `InfiniteOptions`, e.g. `getFooInfiniteOptions()`.
316+
Infinite queries are generated from [query operations](/openapi-ts/configuration/parser#hooks-query-operations) if we detect a [pagination](/openapi-ts/configuration/parser#pagination) parameter. The generated infinite query functions follow the naming convention of SDK functions and by default append `InfiniteOptions`, e.g., `getFooInfiniteOptions()`.
317317

318318
::: code-group
319319

@@ -483,7 +483,7 @@ export default {
483483

484484
:::
485485

486-
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `InfiniteQueryKey`, e.g. `getPetByIdInfiniteQueryKey()`.
486+
Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `InfiniteQueryKey`, e.g., `getPetByIdInfiniteQueryKey()`.
487487

488488
::: code-group
489489

@@ -515,7 +515,7 @@ You can customize the naming and casing pattern for `infiniteQueryKeys` function
515515

516516
## Mutations
517517

518-
Mutations are generated from [mutation operations](/openapi-ts/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g. `addPetMutation()`.
518+
Mutations are generated from [mutation operations](/openapi-ts/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g., `addPetMutation()`.
519519

520520
::: code-group
521521

docs/openapi-ts/plugins/transformers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Before deciding whether transformers are right for you, let's explain how they w
2121

2222
Transformers handle only the most common scenarios. Some of the known limitations are:
2323

24-
- union types are not transformed (e.g. if you have multiple possible response shapes)
24+
- union types are not transformed (e.g., if you have multiple possible response shapes)
2525
- only types defined through `$ref` are transformed
2626
- error responses are not transformed
2727

packages/openapi-python/src/config/output/config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export function getOutput(userConfig: { output: MaybeArray<string | UserOutput>
2424
name: '{{name}}',
2525
suffix: '_gen',
2626
},
27+
module: {},
2728
path: '',
2829
postProcess: [],
2930
preferExportAll: false,
@@ -48,8 +49,8 @@ export function getOutput(userConfig: { output: MaybeArray<string | UserOutput>
4849
},
4950
value: userOutput,
5051
}) as Output;
51-
if (output.importFileExtension && !output.importFileExtension.startsWith('.')) {
52-
output.importFileExtension = `.${output.importFileExtension}`;
52+
if (output.module.extension && !output.module.extension.startsWith('.')) {
53+
output.module.extension = `.${output.module.extension}`;
5354
}
5455
output.postProcess = normalizePostProcess(userOutput.postProcess);
5556
output.source = resolveSource(output);

packages/openapi-python/src/config/output/types.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
import type { BaseOutput, BaseUserOutput, UserPostProcessor } from '@hey-api/shared';
2-
import type { AnyString } from '@hey-api/types';
32

43
import type { PostProcessorPreset } from './postprocess';
54

6-
type ImportFileExtensions = '.py';
7-
8-
export type UserOutput = BaseUserOutput & {
9-
/**
10-
* If specified, this will be the file extension used when importing
11-
* other modules. By default, we don't add a file extension and let the
12-
* runtime resolve it. If you're using moduleResolution `nodenext` or
13-
* `node16`, we default to `.js`.
14-
*
15-
* @default undefined
16-
*/
17-
importFileExtension?: ImportFileExtensions | AnyString | null;
5+
export type UserOutput = BaseUserOutput<'.py'> & {
186
/**
197
* Post-processing commands to run on the output folder, executed in order.
208
*
@@ -35,14 +23,7 @@ export type UserOutput = BaseUserOutput & {
3523
preferExportAll?: boolean;
3624
};
3725

38-
export type Output = BaseOutput & {
39-
/**
40-
* If specified, this will be the file extension used when importing
41-
* other modules. By default, we don't add a file extension and let the
42-
* runtime resolve it. If you're using moduleResolution `nodenext` or
43-
* `node16`, we default to `.js`.
44-
*/
45-
importFileExtension: ImportFileExtensions | AnyString | null | undefined;
26+
export type Output = BaseOutput<'.py'> & {
4627
/**
4728
* Whether `export * from 'module'` should be used when possible
4829
* instead of named exports.

0 commit comments

Comments
 (0)