···11+---
22+"@hey-api/openapi-ts": patch
33+---
44+55+**config**: rename `exportFromIndex` option to `includeInEntry`
+9
.changeset/cold-ties-return.md
···11+---
22+"@hey-api/openapi-ts": minor
33+---
44+55+**BREAKING:** **symbol**: replace `exportFrom` array with `getExportFromFilePath()` function
66+77+### Updated Symbol interface
88+99+The `exportFrom` property has been replaced with the `getExportFromFilePath()` function. This allows you to dynamically determine export paths based on symbol properties. This is a low-level feature, so you're most likely unaffected.
+5
.changeset/deep-buttons-repeat.md
···11+---
22+"@hey-api/openapi-ts": patch
33+---
44+55+**config**: `includeInEntry` accepts function in addition to primitive value
···11+---
22+"@hey-api/shared": patch
33+---
44+55+**config**: `includeInEntry` accepts function in addition to primitive value
+9
.changeset/itchy-beds-start.md
···11+---
22+"@hey-api/codegen-core": minor
33+---
44+55+**BREAKING:** **symbol**: replace `exportFrom` array with `getExportFromFilePath()` function
66+77+### Updated Symbol interface
88+99+The `exportFrom` property has been replaced with the `getExportFromFilePath()` function. This allows you to dynamically determine export paths based on symbol properties. This is a low-level feature, so you're most likely unaffected.
···7788While we try to avoid breaking changes, sometimes it's unavoidable in order to offer you the latest features. This page lists changes that require updates to your code. If you run into a problem with migration, please [open an issue](https://github.com/hey-api/openapi-ts/issues).
991010+## v0.92.0
1111+1212+### Updated Symbol interface
1313+1414+The `exportFrom` property has been replaced with the `getExportFromFilePath()` function. This allows you to dynamically determine export paths based on symbol properties. This is a low-level feature, so you're most likely unaffected.
1515+1016## v0.91.0
11171218### Removed CommonJS (CJS) support
+46-8
docs/openapi-ts/output.md
···58585959You can learn more on the [SDK](/openapi-ts/plugins/sdk) page.
60606161-## Barrel File
6161+## Entry File
62626363`index.ts` is not generated by any specific plugin. It's meant for convenience and by default, it re-exports every artifact generated by default plugins (TypeScript and SDK).
6464···71717272:::
73737474-### Disable index file
7474+### Disable entry file
75757676We recommend importing artifacts from their respective files to avoid ambiguity, but we leave this choice up to you.
7777···8181import type { Pet } from './client/types.gen';
8282```
83838484-If you're not importing artifacts from the index file, you can skip generating it altogether by setting the `output.indexFile` option to `false`.
8484+If you're not importing artifacts from the entry file, you can skip generating it altogether by setting the `output.entryFile` option to `false`.
85858686```js
8787export default {
8888 input: 'hey-api/backend', // sign up at app.heyapi.dev
8989 output: {
9090- indexFile: false, // [!code ++]
9090+ entryFile: false, // [!code ++]
9191 path: 'src/client',
9292 },
9393};
9494```
95959696-### Re-export more files
9696+### Re-export artifacts
9797+9898+You can choose which artifacts should be re-exported from the entry file using the `includeInEntry` option on any plugin. For example, we can re-export all [Zod](/openapi-ts/plugins/zod) plugin artifacts by setting `includeInEntry` to `true`:
9999+100100+::: code-group
971019898-You can choose which files should be re-exported by setting the `exportFromIndex` option to `true` on any plugin. For example, here's how you would re-export [Zod](/openapi-ts/plugins/zod) plugin exports.
102102+```ts [example]
103103+export {
104104+ zAddPetData,
105105+ zAddPetResponse,
106106+ zApiResponse,
107107+ zCategory,
108108+ // ...more exports
109109+} from './zod.gen';
110110+```
99111100100-```js
112112+```js [config]
101113export default {
102114 input: 'hey-api/backend', // sign up at app.heyapi.dev
103115 output: 'src/client',
104116 plugins: [
105117 // ...other plugins
106118 {
107107- exportFromIndex: true, // [!code ++]
119119+ includeInEntry: true, // [!code ++]
108120 name: 'zod',
109121 },
110122 ],
111123};
112124```
125125+126126+:::
127127+128128+Or we can re-export only specific artifacts by providing a predicate function:
129129+130130+::: code-group
131131+132132+```ts [example]
133133+export { zTag } from './zod.gen';
134134+```
135135+136136+```js [config]
137137+export default {
138138+ input: 'hey-api/backend', // sign up at app.heyapi.dev
139139+ output: 'src/client',
140140+ plugins: [
141141+ // ...other plugins
142142+ {
143143+ includeInEntry: (symbol) => symbol.name === 'zTag', // [!code ++]
144144+ name: 'zod',
145145+ },
146146+ ],
147147+};
148148+```
149149+150150+:::
113151114152<!--@include: ../partials/examples.md-->
115153<!--@include: ../partials/sponsors.md-->
+1-1
docs/openapi-ts/plugins/custom.md
···92929393In the file above, we define a `my-plugin` plugin which will generate a `my-plugin.gen.ts` file. We also demonstrate declaring `@hey-api/typescript` as a dependency for our plugin, so we can safely import artifacts from `types.gen.ts`.
94949595-By default, your plugin output won't be re-exported from the `index.ts` file. To enable this feature, add `exportFromIndex: true` to your `config.ts` file.
9595+By default, your plugin output won't be re-exported from the `index.ts` file. To enable this feature, add `includeInEntry: true` to your `config.ts` file.
96969797::: warning
9898Re-exporting your plugin from index file may result in broken output due to naming conflicts. Ensure your exported identifiers are unique.
···3838 "test:watch": "turbo run test:watch",
3939 "test": "turbo run test",
4040 "typecheck": "turbo run typecheck",
4141+ "td": "turbo run dev --filter",
4142 "tt": "turbo run test --filter",
4243 "tw": "turbo run test:watch --filter",
4344 "tu": "turbo run test:update --filter",
···11+/* eslint-disable @typescript-eslint/no-namespace */
22+import type { Plugin } from '@hey-api/shared';
33+44+import type { HeyApiClientHttpxPlugin } from '../../../plugins/@hey-api/client-httpx';
55+66+export interface PluginHandler {
77+ (...args: Parameters<HeyApiClientHttpxPlugin['Handler']>): void;
88+}
99+1010+/**
1111+ * Public Client API.
1212+ */
1313+export namespace Client {
1414+ export type Config = Plugin.Hooks &
1515+ Plugin.UserExports & {
1616+ /**
1717+ * Set a default base URL when creating the client? You can set `baseUrl`
1818+ * to a string which will be used as the base URL. If your input defines
1919+ * server(s), you can set `baseUrl` to a number to pick a specific server
2020+ * to use as the base URL. You can disable setting the base URL by setting
2121+ * `baseUrl` to `false`. By default, `baseUrl` is `true` and it will try to
2222+ * use the first defined server value. If there's none, we won't set a
2323+ * base URL.
2424+ *
2525+ * If the matched URL contains template literals, it will be ignored.
2626+ *
2727+ * @default true
2828+ */
2929+ baseUrl?: string | number | boolean;
3030+ /**
3131+ * Bundle the client module? When `true`, the client module will be copied
3232+ * from the client plugin and bundled with the generated output.
3333+ *
3434+ * @default true
3535+ */
3636+ bundle?: boolean;
3737+ /**
3838+ * Relative path to the runtime configuration file. This file must export
3939+ * a `createClientConfig()` function. The `createClientConfig()` function
4040+ * will be called on client initialization and the returned object will
4141+ * become the client's initial configuration.
4242+ *
4343+ * You may want to initialize your client this way instead of calling
4444+ * `setConfig()`. This is useful for example if you're using Next.js
4545+ * to ensure your client always has the correct values.
4646+ */
4747+ runtimeConfigPath?: string;
4848+ /**
4949+ * Should the type helper for base URL allow only values matching the
5050+ * server(s) defined in the input? By default, `strictBaseUrl` is `false`
5151+ * which will provide type hints and allow you to pass any string.
5252+ *
5353+ * Note that setting `strictBaseUrl` to `true` can produce an invalid
5454+ * build if you specify `baseUrl` which doesn't conform to the type helper.
5555+ *
5656+ * @default false
5757+ */
5858+ strictBaseUrl?: boolean;
5959+ };
6060+}
···11+import type { DefinePlugin, Plugin } from '@hey-api/shared';
22+33+export type UserConfig = Plugin.Name<'@hey-api/client-httpx'> & {
44+ /**
55+ * Set a default base URL when creating the client? You can set `baseUrl`
66+ * to a string which will be used as the base URL. If your input defines
77+ * server(s), you can set `baseUrl` to a number to pick a specific server
88+ * to use as the base URL. You can disable setting the base URL by setting
99+ * `baseUrl` to `false`. By default, `baseUrl` is `true` and it will try to
1010+ * use the first defined server value. If there's none, we won't set a
1111+ * base URL.
1212+ *
1313+ * If the matched URL contains template literals, it will be ignored.
1414+ *
1515+ * @default true
1616+ */
1717+ baseUrl?: string | number | boolean;
1818+};
1919+2020+export type Config = Plugin.Name<'@hey-api/client-httpx'> & {
2121+ baseUrl: string | number | boolean;
2222+};
2323+2424+export type HeyApiClientHttpxPlugin = DefinePlugin<UserConfig, Config>;
···11+import type { FeatureToggle, IR, LinguistLanguages } from '@hey-api/shared';
22+import type { MaybeFunc } from '@hey-api/types';
33+44+import type { CallArgs, DollarPyDsl, ExampleOptions } from '../../../../py-dsl';
55+66+export type UserExamplesConfig = Omit<ExampleOptions, 'payload'> & {
77+ /**
88+ * Whether this feature is enabled.
99+ *
1010+ * @default true
1111+ */
1212+ enabled?: boolean;
1313+ /**
1414+ * The programming language for the generated examples.
1515+ *
1616+ * This is used to display the language label in code blocks in
1717+ * documentation UIs.
1818+ *
1919+ * @default 'Python'
2020+ */
2121+ language?: LinguistLanguages;
2222+ /**
2323+ * Example request payload.
2424+ */
2525+ payload?: MaybeFunc<
2626+ (operation: IR.OperationObject, ctx: DollarPyDsl) => CallArgs | CallArgs[number]
2727+ >;
2828+ /**
2929+ * Transform the generated example string.
3030+ *
3131+ * @param example The generated example string.
3232+ * @param operation The operation the example was generated for.
3333+ * @returns The final example string.
3434+ */
3535+ transform?: (example: string, operation: IR.OperationObject) => string;
3636+};
3737+3838+export type ExamplesConfig = Omit<ExampleOptions, 'payload'> &
3939+ FeatureToggle & {
4040+ /**
4141+ * The programming language for the generated examples.
4242+ *
4343+ * This is used to display the language label in code blocks in
4444+ * documentation UIs.
4545+ */
4646+ language: LinguistLanguages;
4747+ /**
4848+ * Example request payload.
4949+ */
5050+ payload?: MaybeFunc<
5151+ (operation: IR.OperationObject, ctx: DollarPyDsl) => CallArgs | CallArgs[number]
5252+ >;
5353+ /**
5454+ * Transform the generated example string.
5555+ *
5656+ * @param example The generated example string.
5757+ * @param operation The operation the example was generated for.
5858+ * @returns The final example string.
5959+ */
6060+ transform?: (example: string, operation: IR.OperationObject) => string;
6161+ };
···11+export { resolveOperations } from './config';
22+export { resolveStrategy } from './resolve';
33+export type { OperationsConfig, UserOperationsConfig } from './types';
···11-import type { IndexExportOption, NameTransformer } from '@hey-api/shared';
22-import type { DefinePlugin, Plugin } from '@hey-api/shared';
11+import type { DefinePlugin, OperationsStrategy, Plugin } from '@hey-api/shared';
3244-// import type { OperationsStrategy } from '@hey-api/shared';
55-import type { PluginClientNames, PluginValidatorNames } from '../../../plugins/types';
66-77-// import type { ExamplesConfig, UserExamplesConfig } from './examples';
88-// import type { OperationsConfig, UserOperationsConfig } from './operations';
33+import type { PluginClientNames } from '../../../plugins/types';
44+// import type { PluginClientNames, PluginValidatorNames } from '../../../plugins/types';
55+import type { ExamplesConfig, UserExamplesConfig } from './examples';
66+import type { OperationsConfig, UserOperationsConfig } from './operations';
97108export type UserConfig = Plugin.Name<'@hey-api/python-sdk'> &
1111- Plugin.Hooks & {
99+ Plugin.Hooks &
1010+ Plugin.UserExports & {
1211 /**
1312 * Should the generated functions contain auth mechanisms? You may want to
1413 * disable this option if you're handling auth yourself or defining it
···1615 *
1716 * @default true
1817 */
1919- auth?: boolean;
1818+ // auth?: boolean;
2019 /**
2120 * Use an internal client instance to send HTTP requests? This is useful if
2221 * you don't want to manually pass the client to each SDK function.
···2423 * You can customize the selected client output through its plugin. You can
2524 * also set `client` to `true` to automatically choose the client from your
2625 * defined plugins. If we can't detect a client plugin when using `true`, we
2727- * will default to `@hey-api/client-fetch`.
2626+ * will default to `@hey-api/client-httpx`.
2827 *
2928 * @default true
3029 */
···3837 *
3938 * @default false
4039 */
4141- // examples?: boolean | UserExamplesConfig;
4242- /**
4343- * Whether exports should be re-exported in the index file.
4444- *
4545- * @default true
4646- */
4747- exportFromIndex?: boolean;
4040+ examples?: boolean | UserExamplesConfig;
4841 /**
4942 * Define the structure of generated SDK operations.
5043 *
5144 * String shorthand:
5245 * - `'byTags'` – one container per operation tag
5353- * - `'flat'` – standalone functions, no container
5446 * - `'single'` – all operations in a single container
5547 * - custom function for full control
5648 *
5749 * Use the object form for advanced configuration.
5850 *
5959- * @default 'flat'
5151+ * @default 'single'
6052 */
6161- // operations?: OperationsStrategy | UserOperationsConfig;
5353+ operations?: Exclude<OperationsStrategy, 'flat'> | UserOperationsConfig;
6254 /**
6355 * Define how request parameters are structured in generated SDK methods.
6456 *
···7769 *
7870 * @default 'fields'
7971 */
8080- responseStyle?: 'data' | 'fields';
7272+ // responseStyle?: 'data' | 'fields';
8173 /**
8274 * Transform response data before returning. This is useful if you want to
8375 * convert for example ISO strings into Date objects. However, transformation
···8981 *
9082 * @default false
9183 */
9292- transformer?: '@hey-api/transformers' | boolean;
8484+ // transformer?: PluginTransformerNames | boolean;
9385 /**
9486 * Validate request and/or response data against schema before returning.
9587 * This is useful if you want to ensure the request and/or response conforms
···108100 *
109101 * @default false
110102 */
111111- validator?:
112112- | PluginValidatorNames
113113- | boolean
114114- | {
115115- /**
116116- * Validate request data against schema before sending.
117117- *
118118- * Can be a validator plugin name or boolean (true to auto-select, false
119119- * to disable).
120120- *
121121- * @default false
122122- */
123123- request?: PluginValidatorNames | boolean;
124124- /**
125125- * Validate response data against schema before returning.
126126- *
127127- * Can be a validator plugin name or boolean (true to auto-select, false
128128- * to disable).
129129- *
130130- * @default false
131131- */
132132- response?: PluginValidatorNames | boolean;
133133- };
134134-135135- // DEPRECATED OPTIONS BELOW
136136-137137- /**
138138- * Group operation methods into classes? When enabled, you can select which
139139- * classes to export with `sdk.include` and/or transform their names with
140140- * `sdk.classNameBuilder`.
141141- *
142142- * Note that by enabling this option, your SDKs will **NOT**
143143- * support {@link https://developer.mozilla.org/docs/Glossary/Tree_shaking tree-shaking}.
144144- * For this reason, it is disabled by default.
145145- *
146146- * @deprecated Use `operations: { strategy: "byTags" }` or `operations: { strategy: "single" }` instead.
147147- * @default false
148148- */
149149- // eslint-disable-next-line typescript-sort-keys/interface
150150- asClass?: boolean;
151151- /**
152152- * Customize the generated class names. The name variable is obtained from
153153- * your OpenAPI specification tags or `instance` value.
154154- *
155155- * This option has no effect if `sdk.asClass` is `false`.
156156- *
157157- * @deprecated Use `operations: { containerName: "..." }` instead.
158158- */
159159- classNameBuilder?: NameTransformer;
160160- /**
161161- * How should we structure your SDK? By default, we try to infer the ideal
162162- * structure using `operationId` keywords. If you prefer a flatter structure,
163163- * you can set `classStructure` to `off` to disable this behavior.
164164- *
165165- * @deprecated Use `operations: { nesting: "operationId" }` or `operations: { nesting: "id" }` instead.
166166- * @default 'auto'
167167- */
168168- classStructure?: 'auto' | 'off';
169169- /**
170170- * Set `instance` to create an instantiable SDK. Using `true` will use the
171171- * default instance name; in practice, you want to define your own by passing
172172- * a string value.
173173- *
174174- * @deprecated Use `operations: { strategy: "single", containerName: "Name", methods: "instance" }` instead.
175175- * @default false
176176- */
177177- instance?: string | boolean;
178178- /**
179179- * Customise the name of methods within the service. By default,
180180- * `operation.id` is used.
181181- *
182182- * @deprecated Use `operations: { methodName: "..." }` instead.
183183- */
184184- methodNameBuilder?: NameTransformer;
185185- /**
186186- * Use operation ID to generate operation names?
187187- *
188188- * @deprecated Use `operations: { nesting: "operationId" }` or `operations: { nesting: "id" }` instead.
189189- * @default true
190190- */
191191- operationId?: boolean;
192192- /**
193193- * Define shape of returned value from service calls
194194- *
195195- * @deprecated
196196- * @default 'body'
197197- */
198198- response?: 'body' | 'response';
103103+ // validator?:
104104+ // | PluginValidatorNames
105105+ // | boolean
106106+ // | {
107107+ // /**
108108+ // * Validate request data against schema before sending.
109109+ // *
110110+ // * Can be a validator plugin name or boolean (true to auto-select, false
111111+ // * to disable).
112112+ // *
113113+ // * @default false
114114+ // */
115115+ // request?: PluginValidatorNames | boolean;
116116+ // /**
117117+ // * Validate response data against schema before returning.
118118+ // *
119119+ // * Can be a validator plugin name or boolean (true to auto-select, false
120120+ // * to disable).
121121+ // *
122122+ // * @default false
123123+ // */
124124+ // response?: PluginValidatorNames | boolean;
125125+ // };
199126 };
200127201128export type Config = Plugin.Name<'@hey-api/python-sdk'> &
202129 Plugin.Hooks &
203203- IndexExportOption & {
130130+ Plugin.Exports & {
204131 /**
205132 * Should the generated functions contain auth mechanisms? You may want to
206133 * disable this option if you're handling auth yourself or defining it
···208135 *
209136 * @default true
210137 */
211211- auth: boolean;
138138+ // auth: boolean;
212139 /**
213140 * Use an internal client instance to send HTTP requests? This is useful if
214141 * you don't want to manually pass the client to each SDK function.
···216143 * You can customize the selected client output through its plugin. You can
217144 * also set `client` to `true` to automatically choose the client from your
218145 * defined plugins. If we can't detect a client plugin when using `true`, we
219219- * will default to `@hey-api/client-fetch`.
146146+ * will default to `@hey-api/client-httpx`.
220147 *
221148 * @default true
222149 */
···224151 /**
225152 * Configuration for generating SDK code examples.
226153 */
227227- // examples: ExamplesConfig;
154154+ examples: ExamplesConfig;
228155 /**
229156 * Define the structure of generated SDK operations.
230157 */
231231- // operations: OperationsConfig;
158158+ operations: OperationsConfig;
232159 /**
233160 * Define how request parameters are structured in generated SDK methods.
234161 *
···247174 *
248175 * @default 'fields'
249176 */
250250- responseStyle: 'data' | 'fields';
177177+ // responseStyle: 'data' | 'fields';
251178 /**
252179 * Transform response data before returning. This is useful if you want to
253180 * convert for example ISO strings into Date objects. However, transformation
···259186 *
260187 * @default false
261188 */
262262- transformer: '@hey-api/transformers' | false;
189189+ // transformer: PluginTransformerNames | false;
263190 /**
264191 * Validate request and/or response data against schema before returning.
265192 * This is useful if you want to ensure the request and/or response conforms
266193 * to a desired shape. However, validation adds runtime overhead, so it's
267194 * not recommended to use unless absolutely necessary.
268195 */
269269- validator: {
270270- /**
271271- * The validator plugin to use for request validation, or false to disable.
272272- *
273273- * @default false
274274- */
275275- request: PluginValidatorNames | false;
276276- /**
277277- * The validator plugin to use for response validation, or false to disable.
278278- *
279279- * @default false
280280- */
281281- response: PluginValidatorNames | false;
282282- };
283283-284284- // DEPRECATED OPTIONS BELOW
285285-286286- /**
287287- * Define shape of returned value from service calls
288288- *
289289- * @deprecated
290290- * @default 'body'
291291- */
292292- // eslint-disable-next-line typescript-sort-keys/interface
293293- response: 'body' | 'response';
196196+ // validator: {
197197+ // /**
198198+ // * The validator plugin to use for request validation, or false to disable.
199199+ // *
200200+ // * @default false
201201+ // */
202202+ // request: PluginValidatorNames | false;
203203+ // /**
204204+ // * The validator plugin to use for response validation, or false to disable.
205205+ // *
206206+ // * @default false
207207+ // */
208208+ // response: PluginValidatorNames | false;
209209+ // };
294210 };
295211296212export type HeyApiSdkPlugin = DefinePlugin<UserConfig, Config>;
···11+/**
22+ * Matches characters from the start that are not valid Python identifier starts.
33+ * Python identifiers: starts with letter/underscore, followed by letters/digits/underscores.
44+ */
55+const illegalStartCharactersRegExp = /^[^a-zA-Z_]+/;
66+77+/**
88+ * Matches if string contains only digits and optionally decimal point or leading minus.
99+ */
1010+const numberRegExp = /^-?\d+(\.\d+)?$/;
1111+1212+/**
1313+ * Python identifier pattern: starts with letter or underscore,
1414+ * followed by letters, digits, or underscores.
1515+ * Uses Unicode categories for full Python 3 compliance.
1616+ */
1717+const validPythonIdentifierRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/u;
1818+1919+/**
2020+ * Matches if a string looks like a valid Python identifier.
2121+ */
2222+const looksLikeIdentifierRegExp = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
2323+2424+export const regexp = {
2525+ /**
2626+ * Matches characters from the start that are not valid Python identifier starts.
2727+ */
2828+ illegalStartCharacters: illegalStartCharactersRegExp,
2929+ /**
3030+ * Simpler pattern for quick identifier checks.
3131+ */
3232+ looksLikeIdentifier: looksLikeIdentifierRegExp,
3333+ /**
3434+ * Matches if string contains only digits and optionally decimal point or leading minus.
3535+ */
3636+ number: numberRegExp,
3737+ /**
3838+ * Python identifier pattern for validation.
3939+ */
4040+ pythonIdentifier: validPythonIdentifierRegExp,
4141+};
···11+import { keywords } from './keywords';
22+33+type List = ReadonlyArray<string>;
44+55+export class ReservedList {
66+ private _array: List;
77+ private _set: Set<string>;
88+99+ constructor(values: List) {
1010+ this._array = values;
1111+ this._set = new Set(values);
1212+ }
1313+1414+ get '~values'() {
1515+ return this._set;
1616+ }
1717+1818+ /**
1919+ * Updates the reserved list with new values.
2020+ *
2121+ * @param values New reserved values or a function that receives the previous
2222+ * reserved values and returns the new ones.
2323+ */
2424+ set(values: List | ((prev: List) => List)): void {
2525+ const vals = typeof values === 'function' ? values(this._array) : values;
2626+ this._array = vals;
2727+ this._set = new Set(vals);
2828+ }
2929+}
3030+3131+const runtimeReserved = new ReservedList([...keywords.pythonKeywords, ...keywords.pythonBuiltins]);
3232+3333+/**
3434+ * Reserved names for identifiers. These names will not be used
3535+ * for variables, functions, classes, or other identifiers in generated code.
3636+ */
3737+export const reserved = {
3838+ /**
3939+ * Reserved names for runtime identifiers. These names will not be used
4040+ * for variables, functions, classes, or other runtime identifiers in
4141+ * generated code.
4242+ */
4343+ runtime: runtimeReserved,
4444+};
···11-import { describe, it } from 'vitest';
22-31import { py } from '../../../../index';
42import { assertPrintedMatchesSnapshot } from '../../utils';
53
···11-import { describe, it } from 'vitest';
22-31import { py } from '../../../../index';
42import { assertPrintedMatchesSnapshot } from '../../utils';
53
···11-import { describe, it } from 'vitest';
22-31import { py } from '../../../../index';
42import { assertPrintedMatchesSnapshot } from '../../utils';
53
···11-import { describe, it } from 'vitest';
22-31import { py } from '../../../../index';
42import { assertPrintedMatchesSnapshot } from '../../utils';
53
···11import fs from 'node:fs';
22import path from 'node:path';
3344-import { expect } from 'vitest';
55-64import { py } from '../../index';
77-import type { PySourceFile } from '../../nodes/structure/sourceFile';
85import { snapshotsDir, tmpDir } from '../constants';
96107function getCallerFile(): string {
···3835}
39364037export async function assertPrintedMatchesSnapshot(
4141- file: PySourceFile,
3838+ file: py.SourceFile,
4239 filename: string,
4340): Promise<void> {
4441 const result = py.createPrinter().printFile(file);
+123
packages/openapi-python/src/ts-python/index.ts
···11+import type { PyNode as _PyNode, PyNodeBase as _PyNodeBase } from './nodes/base';
22+import type {
33+ PyComprehension as _PyComprehension,
44+ PyComprehensionNode as _PyComprehensionNode,
55+} from './nodes/comprehension';
66+import type { PyClassDeclaration as _PyClassDeclaration } from './nodes/declarations/class';
77+import type { PyFunctionDeclaration as _PyFunctionDeclaration } from './nodes/declarations/function';
88+import type { PyFunctionParameter as _PyFunctionParameter } from './nodes/declarations/functionParameter';
99+import type { PyExpression as _PyExpression } from './nodes/expression';
1010+import type { PyAsyncExpression as _PyAsyncExpression } from './nodes/expressions/async';
1111+import type { PyAwaitExpression as _PyAwaitExpression } from './nodes/expressions/await';
1212+import type {
1313+ PyBinaryExpression as _PyBinaryExpression,
1414+ PyBinaryOperator as _PyBinaryOperator,
1515+} from './nodes/expressions/binary';
1616+import type { PyCallExpression as _PyCallExpression } from './nodes/expressions/call';
1717+import type { PyDictComprehension as _PyDictComprehension } from './nodes/expressions/comprehensions/dict';
1818+import type { PyListComprehension as _PyListComprehension } from './nodes/expressions/comprehensions/list';
1919+import type { PySetComprehension as _PySetComprehension } from './nodes/expressions/comprehensions/set';
2020+import type { PyDictExpression as _PyDictExpression } from './nodes/expressions/dict';
2121+import type { PyFStringExpression as _PyFStringExpression } from './nodes/expressions/fString';
2222+import type { PyGeneratorExpression as _PyGeneratorExpression } from './nodes/expressions/generator';
2323+import type { PyIdentifier as _PyIdentifier } from './nodes/expressions/identifier';
2424+import type { PyLambdaExpression as _PyLambdaExpression } from './nodes/expressions/lambda';
2525+import type { PyListExpression as _PyListExpression } from './nodes/expressions/list';
2626+import type { PyLiteral as _PyLiteral } from './nodes/expressions/literal';
2727+import type { PyMemberExpression as _PyMemberExpression } from './nodes/expressions/member';
2828+import type { PySetExpression as _PySetExpression } from './nodes/expressions/set';
2929+import type { PyTupleExpression as _PyTupleExpression } from './nodes/expressions/tuple';
3030+import type { PyYieldExpression as _PyYieldExpression } from './nodes/expressions/yield';
3131+import type { PyYieldFromExpression as _PyYieldFromExpression } from './nodes/expressions/yieldFrom';
132import { factory } from './nodes/factory';
233import { PyNodeKind } from './nodes/kinds';
3434+import type { PyStatement as _PyStatement } from './nodes/statement';
3535+import type { PyAssignment as _PyAssignment } from './nodes/statements/assignment';
3636+import type {
3737+ PyAugmentedAssignment as _PyAugmentedAssignment,
3838+ PyAugmentedOperator as _PyAugmentedOperator,
3939+} from './nodes/statements/augmentedAssignment';
4040+import type { PyBlock as _PyBlock } from './nodes/statements/block';
4141+import type { PyBreakStatement as _PyBreakStatement } from './nodes/statements/break';
4242+import type { PyContinueStatement as _PyContinueStatement } from './nodes/statements/continue';
4343+import type { PyEmptyStatement as _PyEmptyStatement } from './nodes/statements/empty';
4444+import type { PyExceptClause as _PyExceptClause } from './nodes/statements/except';
4545+import type { PyExpressionStatement as _PyExpressionStatement } from './nodes/statements/expression';
4646+import type { PyForStatement as _PyForStatement } from './nodes/statements/for';
4747+import type { PyIfStatement as _PyIfStatement } from './nodes/statements/if';
4848+import type { PyImportStatement as _PyImportStatement } from './nodes/statements/import';
4949+import type { PyRaiseStatement as _PyRaiseStatement } from './nodes/statements/raise';
5050+import type { PyReturnStatement as _PyReturnStatement } from './nodes/statements/return';
5151+import type { PyTryStatement as _PyTryStatement } from './nodes/statements/try';
5252+import type { PyWhileStatement as _PyWhileStatement } from './nodes/statements/while';
5353+import type { PyWithStatement as _PyWithStatement } from './nodes/statements/with';
5454+import type { PyWithItem as _PyWithItem } from './nodes/statements/withItem';
5555+import type { PyComment as _PyComment } from './nodes/structure/comment';
5656+import type { PySourceFile as _PySourceFile } from './nodes/structure/sourceFile';
5757+import type { PyPrinterOptions as _PyPrinterOptions } from './printer';
358import { createPrinter, printAst } from './printer';
5959+6060+// eslint-disable-next-line @typescript-eslint/no-namespace
6161+export namespace py {
6262+ // Base / Core
6363+ export type Node = _PyNode;
6464+ export type NodeBase = _PyNodeBase;
6565+ export type NodeKind = PyNodeKind;
6666+ export type Expression = _PyExpression;
6767+ export type Statement = _PyStatement;
6868+6969+ // Structure
7070+ export type SourceFile = _PySourceFile;
7171+ export type Comment = _PyComment;
7272+7373+ // Declarations
7474+ export type ClassDeclaration = _PyClassDeclaration;
7575+ export type FunctionDeclaration = _PyFunctionDeclaration;
7676+ export type FunctionParameter = _PyFunctionParameter;
7777+7878+ // Statements
7979+ export type Assignment = _PyAssignment;
8080+ export type AugmentedAssignment = _PyAugmentedAssignment;
8181+ export type AugmentedOperator = _PyAugmentedOperator;
8282+ export type Block = _PyBlock;
8383+ export type BreakStatement = _PyBreakStatement;
8484+ export type ContinueStatement = _PyContinueStatement;
8585+ export type EmptyStatement = _PyEmptyStatement;
8686+ export type ExceptClause = _PyExceptClause;
8787+ export type ExpressionStatement = _PyExpressionStatement;
8888+ export type ForStatement = _PyForStatement;
8989+ export type IfStatement = _PyIfStatement;
9090+ export type ImportStatement = _PyImportStatement;
9191+ export type RaiseStatement = _PyRaiseStatement;
9292+ export type ReturnStatement = _PyReturnStatement;
9393+ export type TryStatement = _PyTryStatement;
9494+ export type WhileStatement = _PyWhileStatement;
9595+ export type WithItem = _PyWithItem;
9696+ export type WithStatement = _PyWithStatement;
9797+9898+ // Expressions
9999+ export type AsyncExpression = _PyAsyncExpression;
100100+ export type AwaitExpression = _PyAwaitExpression;
101101+ export type BinaryExpression = _PyBinaryExpression;
102102+ export type BinaryOperator = _PyBinaryOperator;
103103+ export type CallExpression = _PyCallExpression;
104104+ export type DictExpression = _PyDictExpression;
105105+ export type FStringExpression = _PyFStringExpression;
106106+ export type GeneratorExpression = _PyGeneratorExpression;
107107+ export type Identifier = _PyIdentifier;
108108+ export type LambdaExpression = _PyLambdaExpression;
109109+ export type ListExpression = _PyListExpression;
110110+ export type Literal = _PyLiteral;
111111+ export type MemberExpression = _PyMemberExpression;
112112+ export type SetExpression = _PySetExpression;
113113+ export type TupleExpression = _PyTupleExpression;
114114+ export type YieldExpression = _PyYieldExpression;
115115+ export type YieldFromExpression = _PyYieldFromExpression;
116116+117117+ // Comprehensions
118118+ export type Comprehension = _PyComprehension;
119119+ export type ComprehensionNode = _PyComprehensionNode;
120120+ export type DictComprehension = _PyDictComprehension;
121121+ export type ListComprehension = _PyListComprehension;
122122+ export type SetComprehension = _PySetComprehension;
123123+124124+ // Printer
125125+ export type PrinterOptions = _PyPrinterOptions;
126126+}
41275128export const py = {
6129 PyNodeKind,
···11// TODO: later
22import type { Symbol } from '@hey-api/codegen-core';
33+import type { Plugin, SchemaWithType } from '@hey-api/shared';
3444-import type { Plugin, SchemaWithType } from '../../../../plugins';
55import type { $, DollarTsDsl } from '../../../../ts-dsl';
66import type { FakerJsFakerPlugin } from '../types';
77
···11/* eslint-disable @typescript-eslint/no-namespace */
22-import type { Plugin } from '../../../plugins';
22+import type { Plugin } from '@hey-api/shared';
33+34import type { HeyApiClientAngularPlugin } from '../../../plugins/@hey-api/client-angular';
45import type { HeyApiClientAxiosPlugin } from '../../../plugins/@hey-api/client-axios';
56import type { HeyApiClientFetchPlugin } from '../../../plugins/@hey-api/client-fetch';
···2021 * Public Client API.
2122 */
2223export namespace Client {
2323- export type Config = Plugin.Hooks & {
2424- /**
2525- * Set a default base URL when creating the client? You can set `baseUrl`
2626- * to a string which will be used as the base URL. If your input defines
2727- * server(s), you can set `baseUrl` to a number to pick a specific server
2828- * to use as the base URL. You can disable setting the base URL by setting
2929- * `baseUrl` to `false`. By default, `baseUrl` is `true` and it will try to
3030- * use the first defined server value. If there's none, we won't set a
3131- * base URL.
3232- *
3333- * If the matched URL contains template literals, it will be ignored.
3434- *
3535- * @default true
3636- */
3737- baseUrl?: string | number | boolean;
3838- /**
3939- * Bundle the client module? When `true`, the client module will be copied
4040- * from the client plugin and bundled with the generated output.
4141- *
4242- * @default true
4343- */
4444- bundle?: boolean;
4545- /**
4646- * Whether exports should be re-exported in the index file.
4747- *
4848- * @default false
4949- */
5050- exportFromIndex?: boolean;
5151- /**
5252- * Relative path to the runtime configuration file. This file must export
5353- * a `createClientConfig()` function. The `createClientConfig()` function
5454- * will be called on client initialization and the returned object will
5555- * become the client's initial configuration.
5656- *
5757- * You may want to initialize your client this way instead of calling
5858- * `setConfig()`. This is useful for example if you're using Next.js
5959- * to ensure your client always has the correct values.
6060- */
6161- runtimeConfigPath?: string;
6262- /**
6363- * Should the type helper for base URL allow only values matching the
6464- * server(s) defined in the input? By default, `strictBaseUrl` is `false`
6565- * which will provide type hints and allow you to pass any string.
6666- *
6767- * Note that setting `strictBaseUrl` to `true` can produce an invalid
6868- * build if you specify `baseUrl` which doesn't conform to the type helper.
6969- *
7070- * @default false
7171- */
7272- strictBaseUrl?: boolean;
7373- };
2424+ export type Config = Plugin.Hooks &
2525+ Plugin.UserExports & {
2626+ /**
2727+ * Set a default base URL when creating the client? You can set `baseUrl`
2828+ * to a string which will be used as the base URL. If your input defines
2929+ * server(s), you can set `baseUrl` to a number to pick a specific server
3030+ * to use as the base URL. You can disable setting the base URL by setting
3131+ * `baseUrl` to `false`. By default, `baseUrl` is `true` and it will try to
3232+ * use the first defined server value. If there's none, we won't set a
3333+ * base URL.
3434+ *
3535+ * If the matched URL contains template literals, it will be ignored.
3636+ *
3737+ * @default true
3838+ */
3939+ baseUrl?: string | number | boolean;
4040+ /**
4141+ * Bundle the client module? When `true`, the client module will be copied
4242+ * from the client plugin and bundled with the generated output.
4343+ *
4444+ * @default true
4545+ */
4646+ bundle?: boolean;
4747+ /**
4848+ * Relative path to the runtime configuration file. This file must export
4949+ * a `createClientConfig()` function. The `createClientConfig()` function
5050+ * will be called on client initialization and the returned object will
5151+ * become the client's initial configuration.
5252+ *
5353+ * You may want to initialize your client this way instead of calling
5454+ * `setConfig()`. This is useful for example if you're using Next.js
5555+ * to ensure your client always has the correct values.
5656+ */
5757+ runtimeConfigPath?: string;
5858+ /**
5959+ * Should the type helper for base URL allow only values matching the
6060+ * server(s) defined in the input? By default, `strictBaseUrl` is `false`
6161+ * which will provide type hints and allow you to pass any string.
6262+ *
6363+ * Note that setting `strictBaseUrl` to `true` can produce an invalid
6464+ * build if you specify `baseUrl` which doesn't conform to the type helper.
6565+ *
6666+ * @default false
6767+ */
6868+ strictBaseUrl?: boolean;
6969+ };
7470}
···77} from '@hey-api/shared';
8899export type UserConfig = Plugin.Name<'@hey-api/schemas'> &
1010- Plugin.Hooks & {
1111- /**
1212- * Whether exports should be re-exported in the index file.
1313- *
1414- * @default false
1515- */
1616- exportFromIndex?: boolean;
1010+ Plugin.Hooks &
1111+ Plugin.UserExports & {
1712 /**
1813 * Customise the schema name. By default, `{{name}}Schema` is used. `name` is a
1914 * valid JavaScript/TypeScript identifier, e.g. if your schema name is
···11-import type { IndexExportOption, NameTransformer } from '@hey-api/shared';
22-import type { DefinePlugin, Plugin } from '@hey-api/shared';
33-import type { OperationsStrategy } from '@hey-api/shared';
11+import type { DefinePlugin, NameTransformer, OperationsStrategy, Plugin } from '@hey-api/shared';
4255-import type { PluginClientNames, PluginValidatorNames } from '../../../plugins/types';
33+import type {
44+ PluginClientNames,
55+ PluginTransformerNames,
66+ PluginValidatorNames,
77+} from '../../../plugins/types';
68import type { ExamplesConfig, UserExamplesConfig } from './examples';
79import type { OperationsConfig, UserOperationsConfig } from './operations';
810911export type UserConfig = Plugin.Name<'@hey-api/sdk'> &
1010- Plugin.Hooks & {
1212+ Plugin.Hooks &
1313+ Plugin.UserExports & {
1114 /**
1215 * Should the generated functions contain auth mechanisms? You may want to
1316 * disable this option if you're handling auth yourself or defining it
···3942 */
4043 examples?: boolean | UserExamplesConfig;
4144 /**
4242- * Whether exports should be re-exported in the index file.
4343- *
4444- * @default true
4545- */
4646- exportFromIndex?: boolean;
4747- /**
4845 * Define the structure of generated SDK operations.
4946 *
5047 * String shorthand:
···8885 *
8986 * @default false
9087 */
9191- transformer?: '@hey-api/transformers' | boolean;
8888+ transformer?: PluginTransformerNames | boolean;
9289 /**
9390 * Validate request and/or response data against schema before returning.
9491 * This is useful if you want to ensure the request and/or response conforms
···199196200197export type Config = Plugin.Name<'@hey-api/sdk'> &
201198 Plugin.Hooks &
202202- IndexExportOption & {
199199+ Plugin.Exports & {
203200 /**
204201 * Should the generated functions contain auth mechanisms? You may want to
205202 * disable this option if you're handling auth yourself or defining it
···258255 *
259256 * @default false
260257 */
261261- transformer: '@hey-api/transformers' | false;
258258+ transformer: PluginTransformerNames | false;
262259 /**
263260 * Validate request and/or response data against schema before returning.
264261 * This is useful if you want to ensure the request and/or response conforms
···11import type { SymbolMeta } from '@hey-api/codegen-core';
22import { fromRef, refs } from '@hey-api/codegen-core';
33-import type { IR } from '@hey-api/shared';
44-import { applyNaming } from '@hey-api/shared';
55-import { deduplicateSchema } from '@hey-api/shared';
66-import { pathToJsonPointer, refToName } from '@hey-api/shared';
33+import type { IR, SchemaWithType } from '@hey-api/shared';
44+import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared';
7588-import type { SchemaWithType } from '../../../plugins';
96import { $ } from '../../../ts-dsl';
107import { exportAst } from '../shared/export';
118import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types';
···11-import type { SchemaWithType } from '../../../../plugins';
11+import type { SchemaWithType } from '@hey-api/shared';
22+23import { $ } from '../../../../ts-dsl';
34import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
45import { nullToAst } from './null';
···11-import type { SchemaWithType } from '../../../../plugins';
11+import type { SchemaWithType } from '@hey-api/shared';
22+23import { identifiers } from '../../constants';
34import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
45
···11import { fromRef, ref } from '@hey-api/codegen-core';
22+import type { SchemaWithType } from '@hey-api/shared';
2333-import type { SchemaWithType } from '../../../../plugins';
44import { $ } from '../../../../ts-dsl';
55// import { identifiers } from '../../constants';
66import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
···11-import type { SchemaWithType } from '../../../../plugins';
11+import type { SchemaWithType } from '@hey-api/shared';
22+23import { identifiers } from '../../constants';
34import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
45
···11import type { Refs, Symbol } from '@hey-api/codegen-core';
22-import type { IR } from '@hey-api/shared';
22+import type { IR, Plugin, SchemaWithType } from '@hey-api/shared';
3344-import type { Plugin, SchemaWithType } from '../../../plugins';
54import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/utils/coerce';
65import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats';
76import type { $, DollarTsDsl } from '../../../ts-dsl';
···11import { fromRef } from '@hey-api/codegen-core';
22import type { IR } from '@hey-api/shared';
33-import { applyNaming } from '@hey-api/shared';
44-import { operationResponsesMap } from '@hey-api/shared';
33+import { applyNaming, operationResponsesMap } from '@hey-api/shared';
5465import { exportAst } from './export';
76import type { Ast, IrSchemaToAstOptions } from './types';
+5-10
packages/openapi-ts/src/plugins/valibot/types.ts
···11import type {
22 Casing,
33+ DefinePlugin,
34 FeatureToggle,
44- IndexExportOption,
55 NameTransformer,
66 NamingOptions,
77+ Plugin,
78} from '@hey-api/shared';
88-import type { DefinePlugin, Plugin } from '@hey-api/shared';
991010import type { IApi } from './api';
1111import type { Resolvers } from './resolvers';
12121313export type UserConfig = Plugin.Name<'valibot'> &
1414 Plugin.Hooks &
1515+ Plugin.UserExports &
1516 Resolvers & {
1617 /**
1718 * Casing convention for generated names.
···5960 */
6061 name?: NameTransformer;
6162 };
6262- /**
6363- * Whether exports should be re-exported in the index file.
6464- *
6565- * @default false
6666- */
6767- exportFromIndex?: boolean;
6863 /**
6964 * Enable Valibot metadata support? It's often useful to associate a schema
7065 * with some additional metadata for documentation, code generation, AI
···180175181176export type Config = Plugin.Name<'valibot'> &
182177 Plugin.Hooks &
183183- Resolvers &
184184- IndexExportOption & {
178178+ Plugin.Exports &
179179+ Resolvers & {
185180 /**
186181 * Casing convention for generated names.
187182 */
···11import type { SymbolMeta } from '@hey-api/codegen-core';
22import { fromRef, ref, refs } from '@hey-api/codegen-core';
33-import type { IR } from '@hey-api/shared';
44-import type { SchemaWithType } from '@hey-api/shared';
55-import { applyNaming } from '@hey-api/shared';
66-import { deduplicateSchema } from '@hey-api/shared';
77-import { pathToJsonPointer, refToName } from '@hey-api/shared';
33+import type { IR, SchemaWithType } from '@hey-api/shared';
44+import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared';
8596import { maybeBigInt } from '../../../plugins/shared/utils/coerce';
107import { $ } from '../../../ts-dsl';
···11import type { Refs, Symbol } from '@hey-api/codegen-core';
22-import type { IR } from '@hey-api/shared';
22+import type { IR, Plugin, SchemaWithType } from '@hey-api/shared';
33import type { MaybeArray } from '@hey-api/types';
44import type ts from 'typescript';
5566-import type { Plugin, SchemaWithType } from '../../../plugins';
76import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/utils/coerce';
87import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats';
98import type { $, DollarTsDsl, TsDsl } from '../../../ts-dsl';
···11import { fromRef } from '@hey-api/codegen-core';
22import type { IR } from '@hey-api/shared';
33-import { applyNaming } from '@hey-api/shared';
44-import { operationResponsesMap } from '@hey-api/shared';
33+import { applyNaming, operationResponsesMap } from '@hey-api/shared';
5465import { exportAst } from './export';
76import type { Ast, IrSchemaToAstOptions } from './types';
+5-10
packages/openapi-ts/src/plugins/zod/types.ts
···11import type {
22 Casing,
33+ DefinePlugin,
34 FeatureToggle,
44- IndexExportOption,
55 NameTransformer,
66 NamingOptions,
77+ Plugin,
78} from '@hey-api/shared';
88-import type { DefinePlugin, Plugin } from '@hey-api/shared';
991010import type { IApi } from './api';
1111import type { Resolvers } from './resolvers';
12121313export type UserConfig = Plugin.Name<'zod'> &
1414 Plugin.Hooks &
1515+ Plugin.UserExports &
1516 Resolvers & {
1617 /**
1718 * Casing convention for generated names.
···138139 };
139140 };
140141 };
141141- /**
142142- * Whether exports should be re-exported in the index file.
143143- *
144144- * @default false
145145- */
146146- exportFromIndex?: boolean;
147142 /**
148143 * Enable Zod metadata support? It's often useful to associate a schema with
149144 * some additional metadata for documentation, code generation, AI
···417412418413export type Config = Plugin.Name<'zod'> &
419414 Plugin.Hooks &
420420- Resolvers &
421421- IndexExportOption & {
415415+ Plugin.Exports &
416416+ Resolvers & {
422417 /**
423418 * Casing convention for generated names.
424419 */
+2-5
packages/openapi-ts/src/plugins/zod/v3/plugin.ts
···11import type { SymbolMeta } from '@hey-api/codegen-core';
22import { fromRef, ref, refs } from '@hey-api/codegen-core';
33-import type { IR } from '@hey-api/shared';
44-import type { SchemaWithType } from '@hey-api/shared';
55-import { applyNaming } from '@hey-api/shared';
66-import { deduplicateSchema } from '@hey-api/shared';
77-import { pathToJsonPointer, refToName } from '@hey-api/shared';
33+import type { IR, SchemaWithType } from '@hey-api/shared';
44+import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared';
8596import { maybeBigInt } from '../../../plugins/shared/utils/coerce';
107import { $ } from '../../../ts-dsl';
+2-5
packages/openapi-ts/src/plugins/zod/v4/plugin.ts
···11import type { SymbolMeta } from '@hey-api/codegen-core';
22import { fromRef, ref, refs } from '@hey-api/codegen-core';
33-import type { IR } from '@hey-api/shared';
44-import type { SchemaWithType } from '@hey-api/shared';
55-import { applyNaming } from '@hey-api/shared';
66-import { deduplicateSchema } from '@hey-api/shared';
77-import { pathToJsonPointer, refToName } from '@hey-api/shared';
33+import type { IR, SchemaWithType } from '@hey-api/shared';
44+import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared';
8596import { maybeBigInt } from '../../../plugins/shared/utils/coerce';
107import { $ } from '../../../ts-dsl';
+18-2
packages/openapi-ts/src/ts-dsl/decl/func.ts
···8383 }
8484 }
85858686+ /** Returns true when all required builder calls are present. */
8787+ get isValid(): boolean {
8888+ return this.missingRequiredCalls().length === 0;
8989+ }
9090+8691 /** Switches the function to an arrow function form. */
8792 arrow(): FuncTsDsl<'arrow'> {
8893 this.mode = 'arrow';
···107112 : M extends 'expr'
108113 ? ts.FunctionExpression
109114 : ts.ArrowFunction {
115115+ this.$validate();
110116 const body = this.$node(new BlockTsDsl(...this._do).pretty());
111117112118 if (this.mode === 'decl') {
113113- const name = this.name.toString();
114114- if (!name) throw new Error('Function declaration requires a name');
115119 const node = ts.factory.createFunctionDeclaration(
116120 [...this.$decorators(), ...this.modifiers],
117121 undefined,
···150154 : body,
151155 ) as any;
152156 return this.$docs(node);
157157+ }
158158+159159+ $validate(): asserts this {
160160+ const missing = this.missingRequiredCalls();
161161+ if (missing.length === 0) return;
162162+ throw new Error(`Function ${this.mode} missing ${missing.join(' and ')}`);
163163+ }
164164+165165+ private missingRequiredCalls(): ReadonlyArray<string> {
166166+ const missing: Array<string> = [];
167167+ if (this.mode === 'decl' && !this.name.toString()) missing.push('name');
168168+ return missing;
153169 }
154170}
155171
+20-5
packages/openapi-ts/src/ts-dsl/decl/param.ts
···3939 ctx.analyze(this._type);
4040 }
41414242+ /** Returns true when all required builder calls are present. */
4343+ get isValid(): boolean {
4444+ return this.missingRequiredCalls().length === 0;
4545+ }
4646+4247 /** Sets the parameter type. */
4348 type(type: string | TypeTsDsl): this {
4449 this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
···4651 }
47524853 override toAst() {
4949- const name = this.$pattern() || this.name.toString();
5050- if (!name) {
5151- throw new Error('Param must have either a name or a destructuring pattern');
5252- }
5454+ this.$validate();
5355 return ts.factory.createParameterDeclaration(
5456 this.$decorators(),
5557 undefined,
5656- name,
5858+ this.$pattern() ?? this.name.toString(),
5759 this._optional ? this.$node(new TokenTsDsl().optional()) : undefined,
5860 this.$type(this._type),
5961 this.$value(),
6062 );
6363+ }
6464+6565+ $validate(): asserts this {
6666+ const missing = this.missingRequiredCalls();
6767+ if (missing.length === 0) return;
6868+ throw new Error(`Parameter missing ${missing.join(' and ')}`);
6969+ }
7070+7171+ private missingRequiredCalls(): ReadonlyArray<string> {
7272+ const missing: Array<string> = [];
7373+ if (!this.$pattern() && !this.name.toString())
7474+ missing.push('name or pattern (.array()/.object())');
7575+ return missing;
6176 }
6277}
+22-3
packages/openapi-ts/src/ts-dsl/decl/pattern.ts
···2323 super.analyze(ctx);
2424 }
25252626+ /** Returns true when all required builder calls are present. */
2727+ get isValid(): boolean {
2828+ return this.missingRequiredCalls().length === 0;
2929+ }
3030+2631 /** Defines an array pattern (e.g. `[a, b, c]`). */
2732 array(...props: ReadonlyArray<string> | [ReadonlyArray<string>]): this {
2833 const values = props[0] instanceof Array ? [...props[0]] : (props as ReadonlyArray<string>);
···4954 }
50555156 override toAst() {
5252- if (!this.pattern) {
5353- throw new Error('PatternTsDsl requires object() or array() pattern');
5454- }
5757+ this.$validate();
55585659 if (this.pattern.kind === 'object') {
5760 const elements = Object.entries(this.pattern.values).map(([key, alias]) =>
···7477 }
75787679 throw new Error('PatternTsDsl requires object() or array() pattern');
8080+ }
8181+8282+ $validate(): asserts this is this & {
8383+ pattern:
8484+ | { kind: 'array'; values: ReadonlyArray<string> }
8585+ | { kind: 'object'; values: Record<string, string> };
8686+ } {
8787+ const missing = this.missingRequiredCalls();
8888+ if (missing.length === 0) return;
8989+ throw new Error(`Binding pattern missing ${missing.join(' and ')}`);
9090+ }
9191+9292+ private missingRequiredCalls(): ReadonlyArray<string> {
9393+ const missing: Array<string> = [];
9494+ if (!this.pattern) missing.push('.array() or .object()');
9595+ return missing;
7796 }
78977998 private createSpread(): ts.BindingElement | undefined {
+23-8
packages/openapi-ts/src/ts-dsl/expr/binary.ts
···5050 ctx.analyze(this._expr);
5151 }
52525353+ /** Returns true when all required builder calls are present. */
5454+ get isValid(): boolean {
5555+ return this.missingRequiredCalls().length === 0;
5656+ }
5757+5358 /** Logical AND — `this && expr` */
5459 and(expr: Expr): this {
5560 return this.opAndExpr('&&', expr);
···136141 }
137142138143 override toAst() {
139139- if (!this._op) {
140140- throw new Error('BinaryTsDsl: missing operator');
141141- }
142142- const expr = this.$node(this._expr);
143143- if (!expr) {
144144- throw new Error('BinaryTsDsl: missing right-hand expression');
145145- }
144144+ this.$validate();
146145 const base = this.$node(this._base);
147146 const operator = typeof this._op === 'string' ? this.opToToken(this._op) : this._op;
148148- return ts.factory.createBinaryExpression(base, operator, expr);
147147+ return ts.factory.createBinaryExpression(base, operator, this.$node(this._expr));
148148+ }
149149+150150+ $validate(): asserts this is this & {
151151+ _expr: Ref<Expr>;
152152+ _op: Op;
153153+ } {
154154+ const missing = this.missingRequiredCalls();
155155+ if (missing.length === 0) return;
156156+ throw new Error(`Binary expression missing ${missing.join(' and ')}`);
157157+ }
158158+159159+ private missingRequiredCalls(): ReadonlyArray<string> {
160160+ const missing: Array<string> = [];
161161+ if (!this._op) missing.push('operator (e.g., .eq(), .plus())');
162162+ if (!this._expr) missing.push('right-hand expression');
163163+ return missing;
149164 }
150165151166 /** Sets the binary operator and right-hand operand for this expression. */
+22-6
packages/openapi-ts/src/ts-dsl/expr/prefix.ts
···2323 ctx.analyze(this._expr);
2424 }
25252626+ /** Returns true when all required builder calls are present. */
2727+ get isValid(): boolean {
2828+ return this.missingRequiredCalls().length === 0;
2929+ }
3030+2631 /** Sets the operand (the expression being prefixed). */
2732 expr(expr: string | MaybeTsDsl<ts.Expression>): this {
2833 this._expr = expr;
···4853 }
49545055 override toAst() {
5151- if (!this._expr) {
5252- throw new Error('Missing expression for prefix unary expression');
5353- }
5454- if (!this._op) {
5555- throw new Error('Missing operator for prefix unary expression');
5656- }
5656+ this.$validate();
5757 return ts.factory.createPrefixUnaryExpression(this._op, this.$node(this._expr));
5858+ }
5959+6060+ $validate(): asserts this is this & {
6161+ _expr: string | MaybeTsDsl<ts.Expression>;
6262+ _op: ts.PrefixUnaryOperator;
6363+ } {
6464+ const missing = this.missingRequiredCalls();
6565+ if (missing.length === 0) return;
6666+ throw new Error(`Prefix unary expression missing ${missing.join(' and ')}`);
6767+ }
6868+6969+ private missingRequiredCalls(): ReadonlyArray<string> {
7070+ const missing: Array<string> = [];
7171+ if (!this._expr) missing.push('.expr()');
7272+ if (!this._op) missing.push('operator (e.g., .not(), .neg())');
7373+ return missing;
5874 }
5975}
+24-4
packages/openapi-ts/src/ts-dsl/expr/ternary.ts
···2525 ctx.analyze(this._else);
2626 }
27272828+ /** Returns true when all required builder calls are present. */
2929+ get isValid(): boolean {
3030+ return this.missingRequiredCalls().length === 0;
3131+ }
3232+2833 condition(condition: string | MaybeTsDsl<ts.Expression>) {
2934 this._condition = condition;
3035 return this;
···4146 }
42474348 override toAst() {
4444- if (!this._condition) throw new Error('Missing condition in ternary');
4545- if (!this._then) throw new Error('Missing then expression in ternary');
4646- if (!this._else) throw new Error('Missing else expression in ternary');
4747-4949+ this.$validate();
4850 return ts.factory.createConditionalExpression(
4951 this.$node(this._condition),
5052 undefined,
···5254 undefined,
5355 this.$node(this._else),
5456 );
5757+ }
5858+5959+ $validate(): asserts this is this & {
6060+ _condition: string | MaybeTsDsl<ts.Expression>;
6161+ _else: string | MaybeTsDsl<ts.Expression>;
6262+ _then: string | MaybeTsDsl<ts.Expression>;
6363+ } {
6464+ const missing = this.missingRequiredCalls();
6565+ if (missing.length === 0) return;
6666+ throw new Error(`Ternary expression missing ${missing.join(' and ')}`);
6767+ }
6868+6969+ private missingRequiredCalls(): ReadonlyArray<string> {
7070+ const missing: Array<string> = [];
7171+ if (!this._condition) missing.push('.condition()');
7272+ if (!this._then) missing.push('.do()');
7373+ if (!this._else) missing.push('.otherwise()');
7474+ return missing;
5575 }
5676}
+21-3
packages/openapi-ts/src/ts-dsl/stmt/if.ts
···3737 }
3838 }
39394040+ /** Returns true when all required builder calls are present. */
4141+ get isValid(): boolean {
4242+ return this.missingRequiredCalls().length === 0;
4343+ }
4444+4045 condition(condition: IfCondition): this {
4146 this._condition = condition;
4247 return this;
···4853 }
49545055 override toAst() {
5151- if (!this._condition) throw new Error('Missing condition in if');
5252- if (!this._do) throw new Error('Missing then block in if');
5353-5656+ this.$validate();
5457 return ts.factory.createIfStatement(
5558 this.$node(this._condition),
5659 this.$node(new BlockTsDsl(...this._do).pretty()),
5760 this._else ? this.$node(new BlockTsDsl(...this._else).pretty()) : undefined,
5861 );
6262+ }
6363+6464+ $validate(): asserts this is this & {
6565+ _condition: IfCondition;
6666+ } {
6767+ const missing = this.missingRequiredCalls();
6868+ if (missing.length === 0) return;
6969+ throw new Error(`If statement missing ${missing.join(' and ')}`);
7070+ }
7171+7272+ private missingRequiredCalls(): ReadonlyArray<string> {
7373+ const missing: Array<string> = [];
7474+ if (!this._condition) missing.push('.condition()');
7575+ if (this._do.length === 0) missing.push('.do()');
7676+ return missing;
5977 }
6078}
+20-2
packages/openapi-ts/src/ts-dsl/stmt/try.ts
···5454 }
5555 }
56565757+ /** Returns true when all required builder calls are present. */
5858+ get isValid(): boolean {
5959+ return this.missingRequiredCalls().length === 0;
6060+ }
6161+5762 catch(...items: Array<DoExpr>): this {
5863 this._catch = items;
5964 return this;
···7580 }
76817782 override toAst() {
7878- if (!this._try?.length) throw new Error('Missing try block');
7979-8383+ this.$validate();
8084 const catchParam = this._catchArg ? (this.$node(this._catchArg) as ts.BindingName) : undefined;
81858286 return ts.factory.createTryStatement(
···8791 ),
8892 this._finally ? this.$node(new BlockTsDsl(...this._finally).pretty()) : undefined,
8993 );
9494+ }
9595+9696+ $validate(): asserts this is this & {
9797+ _try: Array<DoExpr>;
9898+ } {
9999+ const missing = this.missingRequiredCalls();
100100+ if (missing.length === 0) return;
101101+ throw new Error(`Try statement missing ${missing.join(' and ')}`);
102102+ }
103103+104104+ private missingRequiredCalls(): ReadonlyArray<string> {
105105+ const missing: Array<string> = [];
106106+ if (!this._try || this._try.length === 0) missing.push('.try()');
107107+ return missing;
90108 }
91109}
+20-3
packages/openapi-ts/src/ts-dsl/stmt/var.ts
···3636 ctx.analyze(this._type);
3737 }
38383939+ /** Returns true when all required builder calls are present. */
4040+ get isValid(): boolean {
4141+ return this.missingRequiredCalls().length === 0;
4242+ }
4343+3944 const(): this {
4045 this.kind = ts.NodeFlags.Const;
4146 return this;
···5863 }
59646065 override toAst() {
6161- const name = this.$pattern() ?? this.$node(this.name);
6262- if (!name) throw new Error('Var must have either a name or a destructuring pattern');
6666+ this.$validate();
6367 const node = ts.factory.createVariableStatement(
6468 this.modifiers,
6569 ts.factory.createVariableDeclarationList(
6670 [
6771 ts.factory.createVariableDeclaration(
6868- name as ts.BindingName,
7272+ this.$pattern() ?? (this.$node(this.name) as ts.BindingName),
6973 undefined,
7074 this.$type(this._type),
7175 this.$value(),
···7579 ),
7680 );
7781 return this.$docs(this.$hint(node));
8282+ }
8383+8484+ $validate(): asserts this {
8585+ const missing = this.missingRequiredCalls();
8686+ if (missing.length === 0) return;
8787+ throw new Error(`Variable declaration missing ${missing.join(' and ')}`);
8888+ }
8989+9090+ private missingRequiredCalls(): ReadonlyArray<string> {
9191+ const missing: Array<string> = [];
9292+ if (!this.$pattern() && !this.name.toString())
9393+ missing.push('name or pattern (.array()/.object())');
9494+ return missing;
7895 }
7996}
+20-3
packages/openapi-ts/src/ts-dsl/token.ts
···4646 }
47474848 override toAst(): ts.Token<K> {
4949- if (!this._kind) {
5050- throw new Error(`Token missing \`.kind(kind)\``);
5151- }
4949+ this.$validate();
5250 // @ts-expect-error
5351 return ts.factory.createToken(this._kind);
5252+ }
5353+5454+ $validate(): asserts this is this & {
5555+ _kind: K;
5656+ } {
5757+ const missing = this.missingRequiredCalls();
5858+ if (missing.length === 0) return;
5959+ throw new Error(`Token missing ${missing.join(' and ')}`);
6060+ }
6161+6262+ private missingRequiredCalls(): ReadonlyArray<string> {
6363+ const missing: Array<string> = [];
6464+ if (!this._kind) missing.push('.kind()');
6565+ return missing;
6666+ }
6767+6868+ /** Returns true when all required builder calls are present. */
6969+ get isValid(): boolean {
7070+ return this.missingRequiredCalls().length === 0;
5471 }
5572}
+21-2
packages/openapi-ts/src/ts-dsl/type/alias.ts
···3535 ctx.analyze(this.value);
3636 }
37373838+ /** Returns true when all required builder calls are present. */
3939+ get isValid(): boolean {
4040+ return this.missingRequiredCalls().length === 0;
4141+ }
4242+3843 /** Sets the type expression on the right-hand side of `= ...`. */
3944 type(node: Value): this {
4045 this.value = node;
···4247 }
43484449 override toAst() {
4545- if (!this.value)
4646- throw new Error(`Type alias '${this.name.toString()}' is missing a type definition`);
5050+ this.$validate();
4751 const node = ts.factory.createTypeAliasDeclaration(
4852 this.modifiers,
4953 this.$node(this.name) as ts.Identifier,
···5155 this.$type(this.value),
5256 );
5357 return this.$docs(node);
5858+ }
5959+6060+ $validate(): asserts this is this & {
6161+ value: Value;
6262+ } {
6363+ const missing = this.missingRequiredCalls();
6464+ if (missing.length === 0) return;
6565+ const name = this.name.toString();
6666+ throw new Error(`Type alias${name ? ` "${name}"` : ''} missing ${missing.join(' and ')}`);
6767+ }
6868+6969+ private missingRequiredCalls(): ReadonlyArray<string> {
7070+ const missing: Array<string> = [];
7171+ if (!this.value) missing.push('.type()');
7272+ return missing;
5473 }
5574}
+22-3
packages/openapi-ts/src/ts-dsl/type/attr.ts
···3737 ctx.analyze(this._right);
3838 }
39394040+ /** Returns true when all required builder calls are present. */
4141+ get isValid(): boolean {
4242+ return this.missingRequiredCalls().length === 0;
4343+ }
4444+4045 base(base?: Base | Ref<Base>): this {
4146 if (isRef(base)) {
4247 this._base = base;
···5257 }
53585459 override toAst() {
5555- if (!this._base) {
5656- throw new Error('TypeAttrTsDsl: missing base for qualified name');
5757- }
6060+ this.$validate();
5861 const left = this.$node(this._base);
5962 if (!ts.isEntityName(left)) {
6063 throw new Error('TypeAttrTsDsl: base must be an EntityName');
6164 }
6265 return ts.factory.createQualifiedName(left, this.$node(this._right) as ts.Identifier);
6666+ }
6767+6868+ $validate(): asserts this is this & {
6969+ _base: Ref<Base>;
7070+ _right: Ref<Right>;
7171+ } {
7272+ const missing = this.missingRequiredCalls();
7373+ if (missing.length === 0) return;
7474+ throw new Error(`Type attribute missing ${missing.join(' and ')}`);
7575+ }
7676+7777+ private missingRequiredCalls(): ReadonlyArray<string> {
7878+ const missing: Array<string> = [];
7979+ if (!this._base) missing.push('.base()');
8080+ if (!this._right) missing.push('.right()');
8181+ return missing;
6382 }
6483}
+20-1
packages/openapi-ts/src/ts-dsl/type/expr.ts
···3939 ctx.analyze(this._exprInput);
4040 }
41414242+ /** Returns true when all required builder calls are present. */
4343+ get isValid(): boolean {
4444+ return this.missingRequiredCalls().length === 0;
4545+ }
4646+4247 /** Accesses a nested type (e.g. `Foo.Bar`). */
4348 attr(right: string | ts.Identifier | TypeAttrTsDsl): this {
4449 this._exprInput = isNode(right)
···4853 }
49545055 override toAst() {
5151- if (!this._exprInput) throw new Error('TypeExpr must have an expression');
5656+ this.$validate();
5257 return ts.factory.createTypeReferenceNode(
5358 this.$type(this._exprInput) as ts.EntityName,
5459 this.$generics(),
5560 );
6161+ }
6262+6363+ $validate(): asserts this is this & {
6464+ _exprInput: Ref<TypeExprExpr>;
6565+ } {
6666+ const missing = this.missingRequiredCalls();
6767+ if (missing.length === 0) return;
6868+ throw new Error(`Type expression missing ${missing.join(' and ')}`);
6969+ }
7070+7171+ private missingRequiredCalls(): ReadonlyArray<string> {
7272+ const missing: Array<string> = [];
7373+ if (!this._exprInput) missing.push('name or .attr()');
7474+ return missing;
5675 }
5776}
5877
+23-5
packages/openapi-ts/src/ts-dsl/type/func.ts
···1717 super.analyze(ctx);
1818 }
19192020+ /** Returns true when all required builder calls are present. */
2121+ get isValid(): boolean {
2222+ return this.missingRequiredCalls().length === 0;
2323+ }
2424+2025 override toAst() {
2121- const returns = this.$returns();
2222- if (returns === undefined) {
2323- throw new Error('Missing return type in function type DSL');
2424- }
2525- const node = ts.factory.createFunctionTypeNode(this.$generics(), this.$params(), returns);
2626+ this.$validate();
2727+ const node = ts.factory.createFunctionTypeNode(
2828+ this.$generics(),
2929+ this.$params(),
3030+ this.$returns()!,
3131+ );
2632 return this.$docs(node);
3333+ }
3434+3535+ $validate(): asserts this {
3636+ const missing = this.missingRequiredCalls();
3737+ if (missing.length === 0) return;
3838+ throw new Error(`Function type missing ${missing.join(' and ')}`);
3939+ }
4040+4141+ private missingRequiredCalls(): ReadonlyArray<string> {
4242+ const missing: Array<string> = [];
4343+ if (this.$returns() === undefined) missing.push('.returns()');
4444+ return missing;
2745 }
2846}
+22
packages/openapi-ts/src/ts-dsl/type/idx.ts
···3131 ctx.analyze(this._index);
3232 }
33333434+ /** Returns true when all required builder calls are present. */
3535+ get isValid(): boolean {
3636+ return this.missingRequiredCalls().length === 0;
3737+ }
3838+3439 base(base: Base): this {
3540 this._base = base;
3641 return this;
···4247 }
43484449 override toAst() {
5050+ this.$validate();
4551 return ts.factory.createIndexedAccessTypeNode(this.$type(this._base), this.$type(this._index));
5252+ }
5353+5454+ $validate(): asserts this is this & {
5555+ _base: Base;
5656+ _index: Index;
5757+ } {
5858+ const missing = this.missingRequiredCalls();
5959+ if (missing.length === 0) return;
6060+ throw new Error(`Indexed access type missing ${missing.join(' and ')}`);
6161+ }
6262+6363+ private missingRequiredCalls(): ReadonlyArray<string> {
6464+ const missing: Array<string> = [];
6565+ if (this._base === undefined) missing.push('.base()');
6666+ if (this._index === undefined) missing.push('.index()');
6767+ return missing;
4668 }
4769}
4870
+21-3
packages/openapi-ts/src/ts-dsl/type/prop.ts
···4242 ctx.analyze(this._type);
4343 }
44444545+ /** Returns true when all required builder calls are present. */
4646+ get isValid(): boolean {
4747+ return this.missingRequiredCalls().length === 0;
4848+ }
4949+4550 /** Sets the property type. */
4651 type(type: TypePropType): this {
4752 this._type = ref(type);
···4954 }
50555156 override toAst() {
5757+ this.$validate();
5258 const name = this.name.toString();
5353- if (!this._type || !name) {
5454- throw new Error(`Type not specified for property '${name}'`);
5555- }
5659 const node = ts.factory.createPropertySignature(
5760 this.modifiers,
5861 this.$node(safePropName(name)),
···6063 this.$type(this._type),
6164 );
6265 return this.$docs(node);
6666+ }
6767+6868+ $validate(): asserts this is this & {
6969+ _type: Ref<TypePropType>;
7070+ } {
7171+ const missing = this.missingRequiredCalls();
7272+ if (missing.length === 0) return;
7373+ const name = this.name.toString();
7474+ throw new Error(`Type property${name ? ` "${name}"` : ''} missing ${missing.join(' and ')}`);
7575+ }
7676+7777+ private missingRequiredCalls(): ReadonlyArray<string> {
7878+ const missing: Array<string> = [];
7979+ if (!this._type) missing.push('.type()');
8080+ return missing;
6381 }
6482}
+2-2
packages/openapi-ts/src/ts-dsl/utils/name.ts
···5050 let sanitized = '';
5151 let index: number;
52525353- const first = name[0]!;
5353+ const first = name[0] ?? '';
5454 regexp.illegalStartCharacters.lastIndex = 0;
5555 if (regexp.illegalStartCharacters.test(first)) {
5656 sanitized += '_';
···6161 }
62626363 while (index < name.length) {
6464- const char = name[index]!;
6464+ const char = name[index] ?? '';
6565 sanitized += /^[\u200c\u200d\p{ID_Continue}]$/u.test(char) ? char : '_';
6666 index += 1;
6767 }
···11-import type { NameConflictResolver } from '@hey-api/codegen-core';
11+import type { NameConflictResolver, Symbol } from '@hey-api/codegen-core';
22import type { MaybeArray } from '@hey-api/types';
3344import type { Plugin } from '../plugins/types';
···1717 enabled: boolean;
1818};
19192020+export type UserIndexExportOption = {
2121+ /**
2222+ * Whether exports should be re-exported from the entry file.
2323+ *
2424+ * - `true` — include all exports
2525+ * - `false` — exclude all exports
2626+ * - `(symbol) => boolean` — include exports matching the predicate
2727+ *
2828+ * @default false
2929+ * @deprecated use `includeInEntry` instead
3030+ */
3131+ exportFromIndex?: boolean | ((symbol: Symbol) => boolean);
3232+ /**
3333+ * Whether exports should be re-exported from the entry file.
3434+ *
3535+ * - `true` — include all exports
3636+ * - `false` — exclude all exports
3737+ * - `(symbol) => boolean` — include exports matching the predicate
3838+ *
3939+ * @default false
4040+ */
4141+ includeInEntry?: boolean | ((symbol: Symbol) => boolean);
4242+};
2043export type IndexExportOption = {
2144 /**
2222- * Whether exports should be re-exported in the index file.
4545+ * Whether exports should be re-exported from the entry file.
4646+ *
4747+ * @deprecated use `includeInEntry` instead
2348 */
2424- exportFromIndex: boolean;
4949+ exportFromIndex: boolean | ((symbol: Symbol) => boolean);
5050+ /**
5151+ * Whether exports should be re-exported from the entry file.
5252+ */
5353+ includeInEntry: boolean | ((symbol: Symbol) => boolean);
2554};
26552756export type NamingOptions = {
···5685 */
5786 clean?: boolean;
5887 /**
8888+ * Whether to generate an entry file that re-exports symbols for convenient imports.
8989+ *
9090+ * Plugins control their inclusion via `includeInEntry`.
9191+ *
9292+ * @default true
9393+ */
9494+ entryFile?: boolean;
9595+ /**
5996 * Optional function to transform file names before they are used.
6097 *
6198 * @param name The original file name.
···95132 */
96133 header?: OutputHeader;
97134 /**
9898- * Should the exports from plugin files be re-exported in the index
9999- * barrel file? By default, this is enabled and only default plugins
100100- * are re-exported.
135135+ * Whether to generate an entry file that re-exports symbols for convenient imports.
136136+ *
137137+ * Plugins control their inclusion via `includeInEntry`.
101138 *
102139 * @default true
140140+ * @deprecated use `entryFile` instead
103141 */
104142 indexFile?: boolean;
105143 /**
···146184 */
147185 clean: boolean;
148186 /**
187187+ * Whether to generate an entry file that re-exports symbols for convenient imports.
188188+ */
189189+ entryFile: boolean;
190190+ /**
149191 * Optional function to transform file names before they are used.
150192 *
151193 * @param name The original file name.
···169211 */
170212 header: OutputHeader;
171213 /**
172172- * Should the exports from plugin files be re-exported in the index
173173- * barrel file? By default, this is enabled and only default plugins
174174- * are re-exported.
214214+ * Whether to generate an entry file that re-exports symbols for convenient imports.
215215+ *
216216+ * @deprecated use `entryFile` instead
175217 */
176218 indexFile: boolean;
177219 /**
+1
packages/shared/src/index.ts
···2222 FeatureToggle,
2323 IndexExportOption,
2424 NamingOptions,
2525+ UserIndexExportOption,
2526} from './config/shared';
2627export type { ValueToObject } from './config/utils/config';
2728export { valueToObject } from './config/utils/config';
-2
packages/shared/src/ir/context.ts
···9898 private registerPlugin<T extends PluginNames>(
9999 name: T,
100100 ): T extends keyof PluginConfigMap ? PluginInstance<PluginConfigMap[T]> : PluginInstance {
101101- // Cast to a loose type internally - the config structure is guaranteed
102102- // by the config resolution layer, not by this method
103101 const plugin = (this.config.plugins as Record<string, Plugin.Config<Plugin.Types>>)[name]!;
104102 const instance = new PluginInstance({
105103 api: plugin.api,
···174174 /**
175175 * Optional output strategy to override default plugin behavior.
176176 *
177177- * Use this to route generated symbols to specific files.
177177+ * Use this to re-export symbols from specific files.
178178+ *
179179+ * @returns The file path(s) that re-export this symbol, or undefined to fallback to default behavior.
180180+ */
181181+ getExportFromFilePath?: (symbol: Symbol) => ReadonlyArray<string> | undefined;
182182+ /**
183183+ * Optional output strategy to override default plugin behavior.
184184+ *
185185+ * Use this to route symbols to specific files.
178186 *
179187 * @returns The file path to output the symbol to, or undefined to fallback to default behavior.
180188 */