···259259 GPT_3_5_TURBO_16K_0613: 'gpt-3.5-turbo-16k-0613',
260260} as const;
261261262262-export type AssistantSupportedModels =
263263- (typeof AssistantSupportedModels)[keyof typeof AssistantSupportedModels];
262262+export type AssistantSupportedModels2 =
263263+ (typeof AssistantSupportedModels2)[keyof typeof AssistantSupportedModels2];
264264265265/**
266266 * Code interpreter tool
···378378 * The format of the output, in one of these options: `json`, `text`, `srt`, `verbose_json`, or `vtt`. For `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`, the only supported format is `json`.
379379 *
380380 */
381381-export type AudioResponseFormat =
382382- (typeof AudioResponseFormat)[keyof typeof AudioResponseFormat];
381381+export type AudioResponseFormat2 =
382382+ (typeof AudioResponseFormat2)[keyof typeof AudioResponseFormat2];
383383384384/**
385385 * A log of a user action or configuration change within this organization.
···389389 * The ID of this log.
390390 */
391391 id: string;
392392- type: AuditLogEventType;
392392+ type: AuditLogEventType2;
393393 /**
394394 * The Unix timestamp (in seconds) of the event.
395395 */
···949949/**
950950 * The event type.
951951 */
952952-export type AuditLogEventType =
953953- (typeof AuditLogEventType)[keyof typeof AuditLogEventType];
952952+export type AuditLogEventType2 =
953953+ (typeof AuditLogEventType2)[keyof typeof AuditLogEventType2];
954954955955/**
956956 * Auto Chunking Strategy
···19111911/**
19121912 * The role of the author of a message
19131913 */
19141914-export type ChatCompletionRole =
19151915- (typeof ChatCompletionRole)[keyof typeof ChatCompletionRole];
19141914+export type ChatCompletionRole2 =
19151915+ (typeof ChatCompletionRole2)[keyof typeof ChatCompletionRole2];
1916191619171917/**
19181918 * Options for streaming response. Only set this when you set `stream: true`.
···26982698 * ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](https://platform.openai.com/docs/models) for descriptions of them.
26992699 *
27002700 */
27012701- model: string | AssistantSupportedModels;
27012701+ model: string | AssistantSupportedModels2;
27022702 /**
27032703 * The name of the assistant. The maximum length is 256 characters.
27042704 *
···27142714 *
27152715 */
27162716 instructions?: string;
27172717- reasoning_effort?: ReasoningEffort;
27172717+ reasoning_effort?: ReasoningEffort2;
27182718 /**
27192719 * A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types `code_interpreter`, `file_search`, or `function`.
27202720 *
···28152815 */
28162816 model: ModelIdsShared;
28172817 modalities?: ResponseModalities;
28182818- verbosity?: Verbosity;
28192819- reasoning_effort?: ReasoningEffort;
28182818+ verbosity?: Verbosity2;
28192819+ reasoning_effort?: ReasoningEffort2;
28202820 /**
28212821 * An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning).
28222822 *
···28562856 type: 'approximate';
28572857 approximate: WebSearchLocation;
28582858 };
28592859- search_context_size?: WebSearchContextSize;
28592859+ search_context_size?: WebSearchContextSize2;
28602860 };
28612861 /**
28622862 * An integer between 0 and 20 specifying the number of most likely tokens to
···30773077 * The model used for the chat completion.
30783078 */
30793079 model: string;
30803080- service_tier?: ServiceTier;
30803080+ service_tier?: ServiceTier2;
30813081 /**
30823082 * This fingerprint represents the backend configuration that the model runs with.
30833083 *
···31513151 * The model to generate the completion.
31523152 */
31533153 model: string;
31543154- service_tier?: ServiceTier;
31543154+ service_tier?: ServiceTier2;
31553155 /**
31563156 * This fingerprint represents the backend configuration that the model runs with.
31573157 * Can be used in conjunction with the `seed` request parameter to understand when backend changes have been made that might impact determinism.
···38593859 *
38603860 */
38613861 file: Blob | File;
38623862- purpose: FilePurpose;
38623862+ purpose: FilePurpose2;
38633863 expires_after?: FileExpirationAfter;
38643864};
38653865···40654065 *
40664066 */
40674067 user?: string;
40684068- input_fidelity?: ImageInputFidelity;
40684068+ input_fidelity?: ImageInputFidelity2;
40694069 /**
40704070 * Edit the image in streaming mode. Defaults to `false`. See the
40714071 * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information.
···44984498 * enrolled in the zero data retention program).
44994499 *
45004500 */
45014501- include?: Array<Includable>;
45014501+ include?: Array<Includable2>;
45024502 /**
45034503 * Whether to allow the model to run tool calls in parallel.
45044504 *
···45384538 /**
45394539 * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the model associated with the assistant. If not, the model associated with the assistant will be used.
45404540 */
45414541- model?: string | AssistantSupportedModels;
45424542- reasoning_effort?: ReasoningEffort;
45414541+ model?: string | AssistantSupportedModels2;
45424542+ reasoning_effort?: ReasoningEffort2;
45434543 /**
45444544 * Overrides the [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) of the assistant. This is useful for modifying the behavior on a per-run basis.
45454545 */
···48364836 *
48374837 */
48384838 prompt?: string;
48394839- response_format?: AudioResponseFormat;
48394839+ response_format?: AudioResponseFormat2;
48404840 /**
48414841 * The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit.
48424842 *
···48664866 * the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`.
48674867 *
48684868 */
48694869- include?: Array<TranscriptionInclude>;
48694869+ include?: Array<TranscriptionInclude2>;
48704870};
4871487148724872/**
···57465746 /**
57475747 * Optional reasoning effort parameter. This is a query parameter used to select responses.
57485748 */
57495749- reasoning_effort?: ReasoningEffort;
57495749+ reasoning_effort?: ReasoningEffort2;
57505750 /**
57515751 * Sampling temperature. This is a query parameter used to select responses.
57525752 */
···61816181/**
61826182 * The ranker to use for the file search. If not specified will use the `auto` ranker.
61836183 */
61846184-export type FileSearchRanker =
61856185- (typeof FileSearchRanker)[keyof typeof FileSearchRanker];
61846184+export type FileSearchRanker2 =
61856185+ (typeof FileSearchRanker2)[keyof typeof FileSearchRanker2];
6186618661876187/**
61886188 * File search tool call ranking options
···61936193 *
61946194 */
61956195export type FileSearchRankingOptions = {
61966196- ranker?: FileSearchRanker;
61966196+ ranker?: FileSearchRanker2;
61976197 /**
61986198 * The score threshold for the file search. All values must be a floating point number between 0 and 1.
61996199 */
···73137313 *
73147314 */
73157315 background?: 'transparent' | 'opaque' | 'auto';
73167316- input_fidelity?: ImageInputFidelity;
73167316+ input_fidelity?: ImageInputFidelity2;
73177317 /**
73187318 * Optional mask for inpainting. Contains `image_url`
73197319 * (string, optional) and `file_id` (string, optional).
···73817381 * for `gpt-image-1`. Supports `high` and `low`. Defaults to `low`.
73827382 *
73837383 */
73847384-export type ImageInputFidelity =
73857385- (typeof ImageInputFidelity)[keyof typeof ImageInputFidelity];
73847384+export type ImageInputFidelity2 =
73857385+ (typeof ImageInputFidelity2)[keyof typeof ImageInputFidelity2];
7386738673877387/**
73887388 * Image generation response
···74947494 * enrolled in the zero data retention program).
74957495 *
74967496 */
74977497-export type Includable = (typeof Includable)[keyof typeof Includable];
74977497+export type Includable2 = (typeof Includable2)[keyof typeof Includable2];
7498749874997499/**
75007500 * Audio input
···88468846 | 'computer-use-preview'
88478847 | 'computer-use-preview-2025-03-11';
8848884888498849-export type ModelIdsShared = string | ChatModel;
88498849+export type ModelIdsShared = string | ChatModel2;
8850885088518851export type ModelResponseProperties = {
88528852 metadata?: Metadata;
···88928892 *
88938893 */
88948894 prompt_cache_key?: string;
88958895- service_tier?: ServiceTier;
88958895+ service_tier?: ServiceTier2;
88968896};
8897889788988898export type ModifyAssistantRequest = {
···89008900 * ID of the model to use. You can use the [List models](https://platform.openai.com/docs/api-reference/models/list) API to see all of your available models, or see our [Model overview](https://platform.openai.com/docs/models) for descriptions of them.
89018901 *
89028902 */
89038903- model?: string | AssistantSupportedModels;
89048904- reasoning_effort?: ReasoningEffort;
89038903+ model?: string | AssistantSupportedModels2;
89048904+ reasoning_effort?: ReasoningEffort2;
89058905 /**
89068906 * The name of the assistant. The maximum length is 256 characters.
89078907 *
···1242412424 *
1242512425 */
1242612426export type Reasoning = {
1242712427- effort?: ReasoningEffort;
1242712427+ effort?: ReasoningEffort2;
1242812428 /**
1242912429 * A summary of the reasoning performed by the model. This can be
1243012430 * useful for debugging and understanding the model's reasoning process.
···1246812468 * on reasoning in a response.
1246912469 *
1247012470 */
1247112471-export type ReasoningEffort =
1247212472- (typeof ReasoningEffort)[keyof typeof ReasoningEffort];
1247112471+export type ReasoningEffort2 =
1247212472+ (typeof ReasoningEffort2)[keyof typeof ReasoningEffort2];
12473124731247412474/**
1247512475 * Reasoning
···1298012980 *
1298112981 */
1298212982export type ResponseError = {
1298312983- code: ResponseErrorCode;
1298312983+ code: ResponseErrorCode2;
1298412984 /**
1298512985 * A human-readable description of the error.
1298612986 *
···1301713017 * The error code for the response.
1301813018 *
1301913019 */
1302013020-export type ResponseErrorCode =
1302113021- (typeof ResponseErrorCode)[keyof typeof ResponseErrorCode];
1302013020+export type ResponseErrorCode2 =
1302113021+ (typeof ResponseErrorCode2)[keyof typeof ResponseErrorCode2];
13022130221302313023/**
1302413024 * Emitted when an error occurs.
···1389613896 */
1389713897 text?: {
1389813898 format?: TextResponseFormatConfiguration;
1389913899- verbosity?: Verbosity;
1389913899+ verbosity?: Verbosity2;
1390013900 };
1390113901 /**
1390213902 * An array of tools the model may call while generating a response. You
···1392313923 *
1392413924 */
1392513925 tool_choice?:
1392613926- | ToolChoiceOptions
1392613926+ | ToolChoiceOptions2
1392713927 | ToolChoiceAllowed
1392813928 | ToolChoiceTypes
1392913929 | ToolChoiceFunction
···1476514765 * The ID of the [assistant](https://platform.openai.com/docs/api-reference/assistants) used for execution of this run.
1476614766 */
1476714767 assistant_id: string;
1476814768- status: RunStatus;
1476814768+ status: RunStatus2;
1476914769 /**
1477014770 * Details on the action required to continue the run. Will be `null` if no action is required.
1477114771 */
···1519015190 * The ranking options for the file search.
1519115191 */
1519215192export type RunStepDetailsToolCallsFileSearchRankingOptionsObject = {
1519315193- ranker: FileSearchRanker;
1519315193+ ranker: FileSearchRanker2;
1519415194 /**
1519515195 * The score threshold for the file search. All values must be a floating point number between 0 and 1.
1519615196 */
···1553715537 * When the `service_tier` parameter is set, the response body will include the `service_tier` value based on the processing mode actually used to serve the request. This response value may be different from the value set in the parameter.
1553815538 *
1553915539 */
1554015540-export type ServiceTier = (typeof ServiceTier)[keyof typeof ServiceTier];
1554015540+export type ServiceTier2 = (typeof ServiceTier2)[keyof typeof ServiceTier2];
15541155411554215542/**
1554315543 * Emitted for each chunk of audio data generated during speech synthesis.
···1593315933 * `required` means the model must call one or more tools.
1593415934 *
1593515935 */
1593615936-export type ToolChoiceOptions =
1593715937- (typeof ToolChoiceOptions)[keyof typeof ToolChoiceOptions];
1593615936+export type ToolChoiceOptions2 =
1593715937+ (typeof ToolChoiceOptions2)[keyof typeof ToolChoiceOptions2];
15938159381593915939/**
1594015940 * Hosted tool
···16100161001610116101export const TranscriptionInclude = { LOGPROBS: 'logprobs' } as const;
16102161021610316103-export type TranscriptionInclude =
1610416104- (typeof TranscriptionInclude)[keyof typeof TranscriptionInclude];
1610316103+export type TranscriptionInclude2 =
1610416104+ (typeof TranscriptionInclude2)[keyof typeof TranscriptionInclude2];
16105161051610616106export type TranscriptionSegment = {
1610716107 /**
···1700017000 * Currently supported values are `low`, `medium`, and `high`.
1700117001 *
1700217002 */
1700317003-export type Verbosity = (typeof Verbosity)[keyof typeof Verbosity];
1700317003+export type Verbosity2 = (typeof Verbosity2)[keyof typeof Verbosity2];
17004170041700517005export type VoiceIdsShared =
1700617006 | string
···1710617106 * search. One of `low`, `medium`, or `high`. `medium` is the default.
1710717107 *
1710817108 */
1710917109-export type WebSearchContextSize =
1711017110- (typeof WebSearchContextSize)[keyof typeof WebSearchContextSize];
1710917109+export type WebSearchContextSize2 =
1711017110+ (typeof WebSearchContextSize2)[keyof typeof WebSearchContextSize2];
17111171111711217112/**
1711317113 * Web search location
···1826918269 * The intended purpose of the uploaded file. One of: - `assistants`: Used in the Assistants API - `batch`: Used in the Batch API - `fine-tune`: Used for fine-tuning - `vision`: Images used for vision fine-tuning - `user_data`: Flexible file type for any purpose - `evals`: Used for eval data sets
1827018270 *
1827118271 */
1827218272-export type FilePurpose = (typeof FilePurpose)[keyof typeof FilePurpose];
1827218272+export type FilePurpose2 = (typeof FilePurpose2)[keyof typeof FilePurpose2];
18273182731827418274export type BatchError = {
1827518275 /**
···1845118451 GPT_3_5_TURBO_16K_0613: 'gpt-3.5-turbo-16k-0613',
1845218452} as const;
18453184531845418454-export type ChatModel = (typeof ChatModel)[keyof typeof ChatModel];
1845418454+export type ChatModel2 = (typeof ChatModel2)[keyof typeof ChatModel2];
18455184551845618456export type CreateThreadAndRunRequestWithoutStream = {
1845718457 /**
···1856718567 /**
1856818568 * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the model associated with the assistant. If not, the model associated with the assistant will be used.
1856918569 */
1857018570- model?: string | AssistantSupportedModels;
1857118571- reasoning_effort?: ReasoningEffort;
1857018570+ model?: string | AssistantSupportedModels2;
1857118571+ reasoning_effort?: ReasoningEffort2;
1857218572 /**
1857318573 * Overrides the [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) of the assistant. This is useful for modifying the behavior on a per-run basis.
1857418574 */
···1864818648/**
1864918649 * The status of the run, which can be either `queued`, `in_progress`, `requires_action`, `cancelling`, `cancelled`, `failed`, `completed`, `incomplete`, or `expired`.
1865018650 */
1865118651-export type RunStatus = (typeof RunStatus)[keyof typeof RunStatus];
1865118651+export type RunStatus2 = (typeof RunStatus2)[keyof typeof RunStatus2];
18652186521865318653/**
1865418654 * The delta containing the fields that have changed on the run step.
···2041920419 /**
2042020420 * Return only events with a `type` in one of these values. For example, `project.created`. For all options, see the documentation for the [audit log object](https://platform.openai.com/docs/api-reference/audit-logs/object).
2042120421 */
2042220422- 'event_types[]'?: Array<AuditLogEventType>;
2042220422+ 'event_types[]'?: Array<AuditLogEventType2>;
2042320423 /**
2042420424 * Return only events performed by these actors. Can be a user ID, a service account ID, or an api key tracking ID.
2042520425 */
···2214322143 * parameter for Response creation above for more information.
2214422144 *
2214522145 */
2214622146- include?: Array<Includable>;
2214622146+ include?: Array<Includable2>;
2214722147 /**
2214822148 * If set to true, the model response data will be streamed to the client
2214922149 * as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).
···2225122251 * parameter for Response creation above for more information.
2225222252 *
2225322253 */
2225422254- include?: Array<Includable>;
2225422254+ include?: Array<Includable2>;
2225522255 };
2225622256 url: '/responses/{response_id}/input_items';
2225722257};
···3030 */
3131 get(key: Key): Value | undefined;
3232 /**
3333- * Gets the key associated with a value.
3333+ * Gets the keys associated with a value.
3434 *
3535 * @param value The value to look up.
3636 */
3737- getKey(value: Value): Key | undefined;
3737+ getKeys(value: Value): Set<Key> | undefined;
3838 /**
3939 * Checks if a key exists in the map.
4040 *
+5-5
packages/codegen-core/src/bindings/utils.ts
···11import type { IFileOut } from '../files/types';
22-import type { ISymbolOut } from '../symbols/types';
22+import type { Symbol } from '../symbols/symbol';
33import type { IBinding } from './types';
4455export const createBinding = ({
···1010}: {
1111 file: IFileOut;
1212 modulePath: string;
1313- symbol: ISymbolOut;
1313+ symbol: Symbol;
1414 symbolFile: IFileOut;
1515}): IBinding => {
1616 const names: Array<string> = [];
···4848 }
4949 } else if (symbol.name && fileResolvedName !== symbol.name) {
5050 name = symbol.name;
5151- binding.aliases[name] = symbol.placeholder;
5151+ binding.aliases[name] = symbol.placeholder!;
5252 }
5353 }
5454- names.push(name);
5454+ names.push(name!);
5555 if (symbol.kind === 'type') {
5656- typeNames.push(name);
5656+ typeNames.push(name!);
5757 }
5858 }
5959 // cast type names to names to allow for cleaner API,
···100100 ...result,
101101 ...file, // clone to avoid mutation
102102 id,
103103+ localNames: new Set(),
103104 resolvedNames: result?.resolvedNames ?? new BiMap(),
104105 symbols: result?.symbols ?? {
105106 body: [],
+4
packages/codegen-core/src/files/types.d.ts
···5353 */
5454 readonly id: number;
5555 /**
5656+ * Names declared in local (non‑top‑level) scopes within this file.
5757+ */
5858+ readonly localNames: Set<string>;
5959+ /**
5660 * Map holding resolved names for symbols in this file.
5761 */
5862 readonly resolvedNames: IBiMap<number, string>;
+4-3
packages/codegen-core/src/index.ts
···44export type {
55 IProjectRenderMeta as ProjectRenderMeta,
66 ISymbolMeta as SymbolMeta,
77-} from './extensions/types';
77+} from './extensions';
88export type {
99 IFileOut as File,
1010 IFileIdentifier as FileIdentifier,
1111 IFileIn as FileIn,
1212} from './files/types';
1313-export type { IOutput as Output } from './output/types';
1313+export type { IOutput as Output } from './output';
1414export { Project } from './project/project';
1515export type { IProject } from './project/types';
1616export type { IRenderer as Renderer } from './renderer/types';
1717export { renderIds } from './renderer/utils';
1818+export { Symbol } from './symbols/symbol';
1819export type {
1919- ISymbolOut as Symbol,
2020 ISymbolIdentifier as SymbolIdentifier,
2121 ISymbolIn as SymbolIn,
2222} from './symbols/types';
2323+export type { ISyntaxNode as SyntaxNode } from './syntax-node';
···11import path from 'node:path';
2233-import type { IProjectRenderMeta } from '../extensions/types';
33+import type { IProjectRenderMeta } from '../extensions';
44import { FileRegistry } from '../files/registry';
55import type { IFileOut, IFileSelector } from '../files/types';
66-import type { IOutput } from '../output/types';
66+import type { IOutput } from '../output';
77import type { IRenderer } from '../renderer/types';
88import { SymbolRegistry } from '../symbols/registry';
99-import type { ISymbolOut } from '../symbols/types';
99+import type { Symbol } from '../symbols/symbol';
1010import type { IProject } from './types';
11111212const externalSourceSymbol = '@';
···133133 return Array.from(fileIds ?? []).map((fileId) => this.files.get(fileId)!);
134134 }
135135136136- private symbolToFileSelector(symbol: ISymbolOut): IFileSelector {
136136+ private symbolToFileSelector(symbol: Symbol): IFileSelector {
137137 if (symbol.external) {
138138 return [externalSourceSymbol, symbol.external];
139139 }
+2-2
packages/codegen-core/src/project/types.d.ts
···11-import type { IProjectRenderMeta } from '../extensions/types';
11+import type { IProjectRenderMeta } from '../extensions';
22import type { IFileOut, IFileRegistry } from '../files/types';
33-import type { IOutput } from '../output/types';
33+import type { IOutput } from '../output';
44import type { IRenderer } from '../renderer/types';
55import type { ISymbolRegistry } from '../symbols/types';
66
+1-1
packages/codegen-core/src/renderer/types.d.ts
···11-import type { IProjectRenderMeta } from '../extensions/types';
11+import type { IProjectRenderMeta } from '../extensions';
22import type { IFileOut } from '../files/types';
33import type { IProject } from '../project/types';
44
···11+import type { ISymbolMeta } from '../extensions';
22+import type { IFileOut } from '../files/types';
33+import { wrapId } from '../renderer/utils';
44+import type { ISyntaxNode } from '../syntax-node';
55+import type { ISymbolIn, SymbolImportKind, SymbolKind } from './types';
66+77+export class Symbol {
88+ /**
99+ * Canonical symbol this stub resolves to, if any.
1010+ *
1111+ * Stubs created during DSL construction may later be associated
1212+ * with a fully registered symbol. Once set, all property lookups
1313+ * should defer to the canonical symbol.
1414+ *
1515+ * @private
1616+ */
1717+ private _canonical?: Symbol;
1818+ /**
1919+ * Private set of direct symbol dependencies.
2020+ *
2121+ * @private
2222+ */
2323+ private readonly _dependencies = new Set<Symbol>();
2424+ /**
2525+ * True if this symbol is exported from its defining file.
2626+ *
2727+ * @default false
2828+ */
2929+ private _exported: boolean;
3030+ /**
3131+ * Names of files (without extension) from which this symbol is re-exported.
3232+ *
3333+ * @default []
3434+ */
3535+ private _exportFrom: ReadonlyArray<string>;
3636+ /**
3737+ * External module name if this symbol is imported from a module not managed
3838+ * by the project (e.g. "zod", "lodash").
3939+ *
4040+ * @default undefined
4141+ */
4242+ private _external?: string;
4343+ /**
4444+ * The file this symbol is ultimately emitted into.
4545+ *
4646+ * @private
4747+ */
4848+ private _file?: IFileOut;
4949+ /**
5050+ * The alias-resolved, conflict-free emitted name.
5151+ *
5252+ * @private
5353+ */
5454+ private _finalName?: string;
5555+ /**
5656+ * Custom strategy to determine file output path.
5757+ *
5858+ * @returns The file path to output the symbol to, or undefined to fallback to default behavior.
5959+ */
6060+ private _getFilePath?: (symbol: Symbol) => string | undefined;
6161+ /**
6262+ * How this symbol should be imported (namespace/default/named).
6363+ *
6464+ * @default 'named'
6565+ */
6666+ private _importKind: SymbolImportKind;
6767+ /**
6868+ * Kind of symbol (class, type, alias, etc.).
6969+ *
7070+ * @default 'var'
7171+ */
7272+ private _kind: SymbolKind;
7373+ /**
7474+ * Arbitrary user metadata.
7575+ *
7676+ * @default undefined
7777+ */
7878+ private _meta?: ISymbolMeta;
7979+ /**
8080+ * Intended user-facing name before conflict resolution.
8181+ *
8282+ * @example "UserModel"
8383+ */
8484+ private _name: string;
8585+ /**
8686+ * Root DSL node that defines this symbol.
8787+ *
8888+ * @private
8989+ */
9090+ private _rootNode?: ISyntaxNode;
9191+9292+ /**
9393+ * Globally unique, stable symbol ID.
9494+ */
9595+ readonly id: number;
9696+ /**
9797+ * Placeholder name for the symbol to be replaced later with the final value.
9898+ *
9999+ * @deprecated
100100+ * @example "_heyapi_31_"
101101+ */
102102+ readonly placeholder: string;
103103+104104+ constructor(input: ISymbolIn, id: number) {
105105+ this._exported = input.exported ?? false;
106106+ this._exportFrom = input.exportFrom ?? [];
107107+ this._external = input.external;
108108+ this._getFilePath = input.getFilePath;
109109+ this.id = id;
110110+ this._importKind = input.importKind ?? 'named';
111111+ this._kind = input.kind ?? 'var';
112112+ this._meta = input.meta;
113113+ this._name = input.name;
114114+ this.placeholder = input.placeholder || wrapId(String(id));
115115+ }
116116+117117+ /**
118118+ * Returns the canonical symbol for this instance.
119119+ *
120120+ * If this symbol was created as a stub, this getter returns
121121+ * the fully registered canonical symbol. Otherwise, it returns
122122+ * the symbol itself.
123123+ */
124124+ get canonical(): Symbol {
125125+ return this._canonical ?? this;
126126+ }
127127+128128+ /**
129129+ * Read-only access to dependencies.
130130+ */
131131+ get dependencies(): ReadonlySet<Symbol> {
132132+ return this.canonical._dependencies;
133133+ }
134134+135135+ /**
136136+ * Indicates whether this symbol is exported from its defining file.
137137+ */
138138+ get exported(): boolean {
139139+ return this.canonical._exported;
140140+ }
141141+142142+ /**
143143+ * Names of files (without extension) that re-export this symbol.
144144+ */
145145+ get exportFrom(): ReadonlyArray<string> {
146146+ return this.canonical._exportFrom;
147147+ }
148148+149149+ /**
150150+ * External module from which this symbol originates, if any.
151151+ */
152152+ get external(): string | undefined {
153153+ return this.canonical._external;
154154+ }
155155+156156+ /**
157157+ * Read‑only accessor for the assigned output file.
158158+ */
159159+ get file(): IFileOut | undefined {
160160+ return this.canonical._file;
161161+ }
162162+163163+ /**
164164+ * Read‑only accessor for the resolved final emitted name.
165165+ */
166166+ get finalName(): string {
167167+ return (
168168+ this.canonical._finalName ||
169169+ this.canonical.placeholder ||
170170+ this.canonical.name
171171+ );
172172+ }
173173+174174+ get getFilePath(): ((symbol: Symbol) => string | undefined) | undefined {
175175+ return this.canonical._getFilePath;
176176+ }
177177+178178+ /**
179179+ * How this symbol should be imported (named/default/namespace).
180180+ */
181181+ get importKind(): SymbolImportKind {
182182+ return this.canonical._importKind;
183183+ }
184184+185185+ /**
186186+ * The symbol's kind (class, type, alias, variable, etc.).
187187+ */
188188+ get kind(): SymbolKind {
189189+ return this.canonical._kind;
190190+ }
191191+192192+ /**
193193+ * Arbitrary user‑provided metadata associated with this symbol.
194194+ */
195195+ get meta(): ISymbolMeta | undefined {
196196+ return this.canonical._meta;
197197+ }
198198+199199+ get name(): string {
200200+ return this.canonical._name;
201201+ }
202202+203203+ /**
204204+ * Read‑only accessor for the defining DSL root node.
205205+ */
206206+ get rootNode(): ISyntaxNode | undefined {
207207+ return this.canonical._rootNode;
208208+ }
209209+210210+ /**
211211+ * Add a direct dependency on another symbol.
212212+ */
213213+ addDependency(symbol: Symbol): void {
214214+ if (symbol !== this) this._dependencies.add(symbol);
215215+ }
216216+217217+ /**
218218+ * Marks this symbol as a stub and assigns its canonical symbol.
219219+ *
220220+ * After calling this, all semantic queries (name, kind, file,
221221+ * meta, etc.) should reflect the canonical symbol's values.
222222+ *
223223+ * @param symbol — The canonical symbol this stub should resolve to.
224224+ */
225225+ setCanonical(symbol: Symbol): void {
226226+ this._canonical = symbol;
227227+ }
228228+229229+ /**
230230+ * Marks the symbol as exported from its file.
231231+ *
232232+ * @param exported — Whether the symbol is exported.
233233+ */
234234+ setExported(exported: boolean): void {
235235+ this._exported = exported;
236236+ }
237237+238238+ /**
239239+ * Records file names that re‑export this symbol.
240240+ *
241241+ * @param list — Source files re‑exporting this symbol.
242242+ */
243243+ setExportFrom(list: ReadonlyArray<string>): void {
244244+ this._exportFrom = list;
245245+ }
246246+247247+ /**
248248+ * Assigns the output file this symbol will be emitted into.
249249+ *
250250+ * This may only be set once.
251251+ */
252252+ setFile(file: IFileOut): void {
253253+ if (this._file && this._file !== file) {
254254+ throw new Error('Symbol is already assigned to a different file.');
255255+ }
256256+ this._file = file;
257257+ }
258258+259259+ /**
260260+ * Assigns the conflict‑resolved final local name for this symbol.
261261+ *
262262+ * This may only be set once.
263263+ */
264264+ setFinalName(name: string): void {
265265+ if (this._finalName && this._finalName !== name) {
266266+ throw new Error('Symbol finalName has already been resolved.');
267267+ }
268268+ this._finalName = name;
269269+ }
270270+271271+ /**
272272+ * Sets how this symbol should be imported.
273273+ *
274274+ * @param kind — The import strategy (named/default/namespace).
275275+ */
276276+ setImportKind(kind: SymbolImportKind): void {
277277+ this._importKind = kind;
278278+ }
279279+280280+ /**
281281+ * Sets the symbol's kind (class, type, alias, variable, etc.).
282282+ *
283283+ * @param kind — The new symbol kind.
284284+ */
285285+ setKind(kind: SymbolKind): void {
286286+ this._kind = kind;
287287+ }
288288+289289+ /**
290290+ * Updates the intended user‑facing name for this symbol.
291291+ *
292292+ * @param name — The new name.
293293+ */
294294+ setName(name: string): void {
295295+ this._name = name;
296296+ }
297297+298298+ /**
299299+ * Binds the DSL node that defines this symbol.
300300+ *
301301+ * This may only be set once.
302302+ */
303303+ setRootNode(node: ISyntaxNode): void {
304304+ if (this._rootNode && this._rootNode !== node) {
305305+ throw new Error('Symbol is already bound to a different root DSL node.');
306306+ }
307307+ this._rootNode = node;
308308+ }
309309+310310+ /**
311311+ * Returns a debug‑friendly string representation identifying the symbol.
312312+ */
313313+ toString(): string {
314314+ return `[Symbol ${this.name}#${this.id}]`;
315315+ }
316316+}
+27-19
packages/codegen-core/src/symbols/types.d.ts
···11-import type { ISymbolMeta } from '../extensions/types';
11+import type { ISymbolMeta } from '../extensions';
22+import type { Symbol } from './symbol';
2334export type ISymbolIdentifier = number | ISymbolMeta;
55+66+export type SymbolImportKind = 'namespace' | 'default' | 'named';
77+88+export type SymbolKind =
99+ | 'alias' // export { a as a2 } from 'a';
1010+ | 'class'
1111+ | 'enum'
1212+ | 'function'
1313+ | 'interface'
1414+ | 'namespace'
1515+ | 'type'
1616+ | 'var';
417518export type ISymbolIn = {
619 /**
···2740 *
2841 * @returns The file path to output the symbol to, or undefined to fallback to default behavior.
2942 */
3030- getFilePath?: (symbol: ISymbolOut) => string | undefined;
3131- /**
3232- * Unique symbol ID. If one is not provided, it will be auto-generated.
3333- */
3434- readonly id?: number;
4343+ getFilePath?: Symbol['getFilePath'];
3544 /**
3645 * Kind of import if this symbol represents an import.
3746 */
3838- importKind?: 'namespace' | 'default' | 'named';
4747+ importKind?: SymbolImportKind;
3948 /**
4049 * Kind of symbol.
4150 */
4242- kind?: 'class' | 'function' | 'type';
5151+ kind?: SymbolKind;
4352 /**
4453 * Arbitrary metadata about the symbol.
4554 *
···4756 */
4857 meta?: ISymbolMeta;
4958 /**
5050- * The desired name for the symbol within its file. If there are multiple symbols
5151- * with the same desired name, this might not end up being the actual name.
5959+ * The intended, user-facing name of the symbol before any conflict resolution.
6060+ * It is **not** guaranteed to be the final emitted name — aliasing may occur if the
6161+ * file contains conflicting local identifiers or other symbols with the same intended name.
5262 *
5363 * @example "UserModel"
5464 */
5555- name?: string;
6565+ name: string;
5666 /**
5767 * Placeholder name for the symbol to be replaced later with the final value.
5868 *
6969+ * @deprecated
5970 * @example "_heyapi_31_"
6071 */
6172 readonly placeholder?: string;
6273};
63746464-export type ISymbolOut = Omit<ISymbolIn, 'id' | 'placeholder'> &
6565- Pick<Required<ISymbolIn>, 'id' | 'placeholder'>;
6666-6775export interface ISymbolRegistry {
6876 /**
6977 * Get a symbol.
···7179 * @param identifier Symbol identifier to reference.
7280 * @returns The symbol, or undefined if not found.
7381 */
7474- get(identifier: ISymbolIdentifier): ISymbolOut | undefined;
8282+ get(identifier: ISymbolIdentifier): Symbol | undefined;
7583 /**
7684 * Returns the value associated with a symbol ID.
7785 *
···105113 * @param filter Metadata filter to query symbols by.
106114 * @returns Array of symbols matching the filter.
107115 */
108108- query(filter: ISymbolMeta): ReadonlyArray<ISymbolOut>;
116116+ query(filter: ISymbolMeta): ReadonlyArray<Symbol>;
109117 /**
110118 * References a symbol.
111119 *
112120 * @param meta Metadata filter to reference symbol by.
113121 * @returns The referenced symbol.
114122 */
115115- reference(meta: ISymbolMeta): ISymbolOut;
123123+ reference(meta: ISymbolMeta): Symbol;
116124 /**
117125 * Register a symbol globally.
118126 *
···121129 * @param symbol Symbol to register.
122130 * @returns The registered symbol.
123131 */
124124- register(symbol: ISymbolIn): ISymbolOut;
132132+ register(symbol: ISymbolIn): Symbol;
125133 /**
126134 * Get all symbols in the order they were registered.
127135 *
128136 * @returns Array of all registered symbols, in insert order.
129137 */
130130- registered(): IterableIterator<ISymbolOut>;
138138+ registered(): IterableIterator<Symbol>;
131139 /**
132140 * Sets a value for a symbol by its ID.
133141 *
+20
packages/codegen-core/src/syntax-node.d.ts
···11+import type { Symbol } from './symbols/symbol';
22+33+export interface ISyntaxNode {
44+ /**
55+ * Return local names introduced by this node.
66+ */
77+ getLocalNames(): Iterable<string>;
88+ /**
99+ * Return symbols referenced directly by this node.
1010+ */
1111+ getSymbols(): Iterable<Symbol>;
1212+ /**
1313+ * Rewrite local identifiers based on a rename map.
1414+ */
1515+ rewriteIdentifiers(map: Map<string, string>): void;
1616+ /**
1717+ * Walk this node and its children with a visitor.
1818+ */
1919+ traverse(visitor: (node: ISyntaxNode) => void): void;
2020+}
···267267 * This is a model with one property containing a circular reference
268268 */
269269export const vModelWithCircularReference: v.GenericSchema = v.object({
270270- prop: v.optional(v.lazy(() => vModelWithCircularReference))
270270+ prop: v.optional(v.lazy(() => vModelWithCircularReference2))
271271});
272272273273/**
···343343 * This is a model with one property containing a circular reference
344344 */
345345export const vModelWithCircularReference: v.GenericSchema = v.object({
346346- prop: v.optional(v.lazy(() => vModelWithCircularReference))
346346+ prop: v.optional(v.lazy(() => vModelWithCircularReference2))
347347});
348348349349/**
···343343 * This is a model with one property containing a circular reference
344344 */
345345export const vModelWithCircularReference: v.GenericSchema = v.object({
346346- prop: v.optional(v.lazy(() => vModelWithCircularReference))
346346+ prop: v.optional(v.lazy(() => vModelWithCircularReference2))
347347});
348348349349/**
···293293 * This is a model with one property containing a circular reference
294294 */
295295export const zModelWithCircularReference: z.AnyZodObject = z.object({
296296- prop: z.lazy(() => zModelWithCircularReference).optional()
296296+ prop: z.lazy(() => zModelWithCircularReference2).optional()
297297});
298298299299/**
···391391 * This is a model with one property containing a circular reference
392392 */
393393export const zModelWithCircularReference: z.AnyZodObject = z.object({
394394- prop: z.lazy(() => zModelWithCircularReference).optional()
394394+ prop: z.lazy(() => zModelWithCircularReference2).optional()
395395});
396396397397/**
···394394 * This is a model with one property containing a circular reference
395395 */
396396export const zModelWithCircularReference: z.AnyZodObject = z.object({
397397- prop: z.lazy(() => zModelWithCircularReference).optional()
397397+ prop: z.lazy(() => zModelWithCircularReference2).optional()
398398});
399399400400/**
···293293 * This is a model with one property containing a circular reference
294294 */
295295export const zModelWithCircularReference: z.AnyZodObject = z.object({
296296- prop: z.lazy(() => zModelWithCircularReference).optional()
296296+ prop: z.lazy(() => zModelWithCircularReference2).optional()
297297});
298298299299/**
···391391 * This is a model with one property containing a circular reference
392392 */
393393export const zModelWithCircularReference: z.AnyZodObject = z.object({
394394- prop: z.lazy(() => zModelWithCircularReference).optional()
394394+ prop: z.lazy(() => zModelWithCircularReference2).optional()
395395});
396396397397/**
···394394 * This is a model with one property containing a circular reference
395395 */
396396export const zModelWithCircularReference: z.AnyZodObject = z.object({
397397- prop: z.lazy(() => zModelWithCircularReference).optional()
397397+ prop: z.lazy(() => zModelWithCircularReference2).optional()
398398});
399399400400/**
···11+// TODO: symbol should be protected, but needs to be public to satisfy types
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
13import ts from 'typescript';
2435export type MaybeArray<T> = T | ReadonlyArray<T>;
4655-export interface ITsDsl<T extends ts.Node = ts.Node> {
77+export interface ITsDsl<T extends ts.Node = ts.Node> extends SyntaxNode {
88+ /** Render this DSL node into a concrete TypeScript AST node. */
69 $render(): T;
710}
8111212+export type Constructor<T = ITsDsl> = new (...args: ReadonlyArray<any>) => T;
1313+914export abstract class TsDsl<T extends ts.Node = ts.Node> implements ITsDsl<T> {
1515+ /** Walk this node and its children with a visitor. */
1616+ abstract traverse(visitor: (node: SyntaxNode) => void): void;
1717+1818+ /** Render this DSL node into a concrete TypeScript AST node. */
1019 abstract $render(): T;
2020+2121+ /** Parent DSL node in the constructed syntax tree. */
2222+ protected parent?: TsDsl<any>;
2323+2424+ /** The codegen symbol associated with this node. */
2525+ symbol?: Symbol;
11261227 /** Conditionally applies a callback to this builder. */
1328 $if<T extends TsDsl, V, R extends TsDsl = T>(
···8499 return this;
85100 }
86101102102+ /** Returns all locally declared names within this node. */
103103+ getLocalNames(): Iterable<string> {
104104+ return [];
105105+ }
106106+107107+ /** Returns all symbols referenced by this node (directly or through children). */
108108+ getSymbols(): Iterable<Symbol> {
109109+ return [];
110110+ }
111111+112112+ /** Rewrites internal identifier nodes after final name resolution. */
113113+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
114114+ rewriteIdentifiers(_map: Map<string, string>): void {
115115+ // noop
116116+ }
117117+118118+ /** Assigns the parent DSL node, enforcing a single-parent invariant. */
119119+ setParent(parent: TsDsl<any>): this {
120120+ if (this.parent && this.parent !== parent) {
121121+ throw new Error(
122122+ `DSL node already has a parent (${this.parent.constructor.name}); cannot reassign to ${parent.constructor.name}.`,
123123+ );
124124+ }
125125+ this.parent = parent;
126126+ return this;
127127+ }
128128+87129 protected $maybeId<T extends string | ts.Expression>(
88130 expr: T,
89131 ): T extends string ? ts.Identifier : T {
···132174 return this.unwrap(value as any) as TypeOfMaybe<I>;
133175 }
134176177177+ /** Returns the root symbol associated with this DSL subtree. */
178178+ protected getRootSymbol(): Symbol | undefined {
179179+ // eslint-disable-next-line @typescript-eslint/no-this-alias
180180+ let n: TsDsl<any> | undefined = this;
181181+ while (n) {
182182+ if (n.symbol) return n.symbol;
183183+ n = n.parent;
184184+ }
185185+ return undefined;
186186+ }
187187+188188+ /** Unwraps nested DSL nodes into raw TypeScript AST nodes. */
135189 protected unwrap<I>(value: I): I extends TsDsl<infer N> ? N : I {
136190 return (
137191 value instanceof TsDsl ? value.$render() : value
+48-19
packages/openapi-ts/src/ts-dsl/decl/class.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1920import { MethodTsDsl } from './method';
20212122export class ClassTsDsl extends TsDsl<ts.ClassDeclaration> {
2222- protected heritageClauses: Array<ts.HeritageClause> = [];
2323+ protected baseClass?: Symbol | string;
2324 protected body: Array<MaybeTsDsl<ts.ClassElement | NewlineTsDsl>> = [];
2425 protected modifiers = createModifierAccessor(this);
2526 protected name: string;
26272727- constructor(name: string) {
2828+ constructor(name: Symbol | string) {
2829 super();
2929- this.name = name;
3030+ if (typeof name === 'string') {
3131+ this.name = name;
3232+ return;
3333+ }
3434+ this.name = name.finalName;
3535+ this.symbol = name;
3636+ this.symbol.setKind('class');
3737+ this.symbol.setRootNode(this);
3038 }
31393240 /** Adds one or more class members (fields, methods, etc.). */
3341 do(...items: ReadonlyArray<MaybeTsDsl<ts.ClassElement | ts.Node>>): this {
3434- // @ts-expect-error --- IGNORE ---
3535- this.body.push(...items);
4242+ for (const item of items) {
4343+ if (item && typeof item === 'object' && 'setParent' in item) {
4444+ item.setParent(this);
4545+ }
4646+ // @ts-expect-error --- IGNORE ---
4747+ this.body.push(item);
4848+ }
3649 return this;
3750 }
38513939- /** Adds a base class to extend from. */
4040- extends(base?: string | ts.Expression | false | null): this {
5252+ /** Records a base class to extend from without rendering early. */
5353+ extends(base?: Symbol | string): this {
4154 if (!base) return this;
4242- this.heritageClauses.push(
4343- ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [
4444- ts.factory.createExpressionWithTypeArguments(
4545- this.$maybeId(base),
4646- undefined,
4747- ),
4848- ]),
4949- );
5555+ this.baseClass = base;
5656+ if (typeof base !== 'string') {
5757+ const symbol = this.getRootSymbol();
5858+ if (symbol) symbol.addDependency(base);
5959+ }
5060 return this;
5161 }
52625363 /** Adds a class field. */
5464 field(name: string, fn?: (f: FieldTsDsl) => void): this {
5555- const f = new FieldTsDsl(name, fn);
6565+ const f = new FieldTsDsl(name, fn).setParent(this);
5666 this.body.push(f);
5767 return this;
5868 }
59696070 /** Adds a class constructor. */
6171 init(fn?: (i: InitTsDsl) => void): this {
6262- const i = new InitTsDsl(fn);
7272+ const i = new InitTsDsl(fn).setParent(this);
6373 this.body.push(i);
6474 return this;
6575 }
66766777 /** Adds a class method. */
6878 method(name: string, fn?: (m: MethodTsDsl) => void): this {
6969- const m = new MethodTsDsl(name, fn);
7979+ const m = new MethodTsDsl(name, fn).setParent(this);
7080 this.body.push(m);
7181 return this;
7282 }
···7585 newline(): this {
7686 this.body.push(new NewlineTsDsl());
7787 return this;
8888+ }
8989+9090+ /** Walk this node and its children with a visitor. */
9191+ traverse(visitor: (node: SyntaxNode) => void): void {
9292+ console.log(visitor);
7893 }
79948095 /** Builds the `ClassDeclaration` node. */
···8499 [...this.$decorators(), ...this.modifiers.list()],
85100 this.name,
86101 this.$generics(),
8787- this.heritageClauses,
102102+ this._renderHeritage(),
88103 body,
89104 );
105105+ }
106106+107107+ /** Builds heritage clauses (extends). */
108108+ private _renderHeritage(): ReadonlyArray<ts.HeritageClause> {
109109+ if (!this.baseClass) return [];
110110+ const id =
111111+ typeof this.baseClass === 'string'
112112+ ? this.$maybeId(this.baseClass)
113113+ : this.$maybeId(this.baseClass.finalName);
114114+ return [
115115+ ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [
116116+ ts.factory.createExpressionWithTypeArguments(id, undefined),
117117+ ]),
118118+ ];
90119 }
91120}
92121
+19-8
packages/openapi-ts/src/ts-dsl/decl/decorator.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···78import { ArgsMixin } from '../mixins/args';
89910export class DecoratorTsDsl extends TsDsl<ts.Decorator> {
1010- protected name: string | ts.Expression;
1111+ protected name: Symbol | string | MaybeTsDsl<ts.Expression>;
11121213 constructor(
1313- name: string | ts.Expression,
1414+ name: Symbol | string | MaybeTsDsl<ts.Expression>,
1415 ...args: ReadonlyArray<string | MaybeTsDsl<ts.Expression>>
1516 ) {
1617 super();
1718 this.name = name;
1919+ if (typeof name !== 'string' && 'id' in name) {
2020+ const symbol = this.getRootSymbol();
2121+ if (symbol) symbol.addDependency(name);
2222+ }
1823 this.args(...args);
2424+ }
2525+2626+ /** Walk this node and its children with a visitor. */
2727+ traverse(visitor: (node: SyntaxNode) => void): void {
2828+ console.log(visitor);
1929 }
20302131 $render(): ts.Decorator {
3232+ const target =
3333+ typeof this.name !== 'string' && 'id' in this.name
3434+ ? this.$maybeId(this.name.finalName)
3535+ : this.$node(this.name);
3636+2237 const args = this.$args();
2338 return ts.factory.createDecorator(
2439 args.length
2525- ? ts.factory.createCallExpression(
2626- this.$maybeId(this.name),
2727- undefined,
2828- args,
2929- )
3030- : this.$maybeId(this.name),
4040+ ? ts.factory.createCallExpression(target, undefined, args)
4141+ : target,
3142 );
3243 }
3344}
+15-2
packages/openapi-ts/src/ts-dsl/decl/enum.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···2021 private _name: string | ts.Identifier;
2122 protected modifiers = createModifierAccessor(this);
22232323- constructor(name: string | ts.Identifier, fn?: (e: EnumTsDsl) => void) {
2424+ constructor(name: Symbol | string, fn?: (e: EnumTsDsl) => void) {
2425 super();
2525- this._name = name;
2626+ if (typeof name === 'string') {
2727+ this._name = name;
2828+ } else {
2929+ this._name = name.finalName;
3030+ this.symbol = name;
3131+ this.symbol.setKind('enum');
3232+ this.symbol.setRootNode(this);
3333+ }
2634 fn?.(this);
2735 }
2836···3745 members(...members: ReadonlyArray<EnumMemberTsDsl>): this {
3846 this._members.push(...members);
3947 return this;
4848+ }
4949+5050+ /** Walk this node and its children with a visitor. */
5151+ traverse(visitor: (node: SyntaxNode) => void): void {
5252+ console.log(visitor);
4053 }
41544255 /** Renders the enum declaration. */
+6
packages/openapi-ts/src/ts-dsl/decl/field.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···3132 type(type: string | TypeTsDsl): this {
3233 this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
3334 return this;
3535+ }
3636+3737+ /** Walk this node and its children with a visitor. */
3838+ traverse(visitor: (node: SyntaxNode) => void): void {
3939+ console.log(visitor);
3440 }
35413642 /** Builds the `PropertyDeclaration` node. */
+22-9
packages/openapi-ts/src/ts-dsl/decl/func.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···2930 ? ts.FunctionExpression
3031 : ts.ArrowFunction
3132> {
3232- protected mode: FuncMode;
3333+ protected mode?: FuncMode;
3334 protected modifiers = createModifierAccessor(this);
3435 protected name?: string;
3536 protected _returns?: TypeTsDsl;
36373738 constructor();
3839 constructor(fn: (f: ImplFuncTsDsl<'arrow'>) => void);
3939- constructor(name: string);
4040- constructor(name: string, fn: (f: ImplFuncTsDsl<'decl'>) => void);
4040+ constructor(name: Symbol | string);
4141+ constructor(name: Symbol | string, fn: (f: ImplFuncTsDsl<'decl'>) => void);
4142 constructor(
4242- nameOrFn?: string | ((f: ImplFuncTsDsl<'arrow'>) => void),
4343+ nameOrFn?: Symbol | string | ((f: ImplFuncTsDsl<'arrow'>) => void),
4344 fn?: (f: ImplFuncTsDsl<'decl'>) => void,
4445 ) {
4546 super();
4646- if (typeof nameOrFn === 'string') {
4747- this.name = nameOrFn;
4747+ if (typeof nameOrFn === 'function') {
4848+ this.mode = 'arrow';
4949+ nameOrFn(this as unknown as FuncTsDsl<'arrow'>);
5050+ } else if (nameOrFn) {
4851 this.mode = 'decl';
5252+ if (typeof nameOrFn === 'string') {
5353+ this.name = nameOrFn;
5454+ } else {
5555+ this.name = nameOrFn.finalName;
5656+ this.symbol = nameOrFn;
5757+ this.symbol.setKind('function');
5858+ this.symbol.setRootNode(this);
5959+ }
4960 fn?.(this as unknown as FuncTsDsl<'decl'>);
5050- } else {
5151- this.mode = 'arrow';
5252- nameOrFn?.(this as unknown as FuncTsDsl<'arrow'>);
5361 }
5462 }
5563···7583 returns(type: string | TypeTsDsl): this {
7684 this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
7785 return this;
8686+ }
8787+8888+ /** Walk this node and its children with a visitor. */
8989+ traverse(visitor: (node: SyntaxNode) => void): void {
9090+ console.log(visitor);
7891 }
79928093 $render(): M extends 'decl'
+6
packages/openapi-ts/src/ts-dsl/decl/getter.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl } from '../base';
···2526 super();
2627 this.name = name;
2728 fn?.(this);
2929+ }
3030+3131+ /** Walk this node and its children with a visitor. */
3232+ traverse(visitor: (node: SyntaxNode) => void): void {
3333+ console.log(visitor);
2834 }
29353036 $render(): ts.GetAccessorDeclaration {
+6
packages/openapi-ts/src/ts-dsl/decl/init.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl } from '../base';
···2021 constructor(fn?: (i: InitTsDsl) => void) {
2122 super();
2223 fn?.(this);
2424+ }
2525+2626+ /** Walk this node and its children with a visitor. */
2727+ traverse(visitor: (node: SyntaxNode) => void): void {
2828+ console.log(visitor);
2329 }
24302531 /** Builds the `ConstructorDeclaration` node. */
+6
packages/openapi-ts/src/ts-dsl/decl/member.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···2223 } else {
2324 this.value(value);
2425 }
2626+ }
2727+2828+ /** Walk this node and its children with a visitor. */
2929+ traverse(visitor: (node: SyntaxNode) => void): void {
3030+ console.log(visitor);
2531 }
26322733 /** Sets the enum member value. */
+6
packages/openapi-ts/src/ts-dsl/decl/method.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···3637 returns(type: string | TypeTsDsl): this {
3738 this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
3839 return this;
4040+ }
4141+4242+ /** Walk this node and its children with a visitor. */
4343+ traverse(visitor: (node: SyntaxNode) => void): void {
4444+ console.log(visitor);
3945 }
40464147 /** Builds the `MethodDeclaration` node. */
+6
packages/openapi-ts/src/ts-dsl/decl/param.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···2526 } else {
2627 name(this);
2728 }
2929+ }
3030+3131+ /** Walk this node and its children with a visitor. */
3232+ traverse(visitor: (node: SyntaxNode) => void): void {
3333+ console.log(visitor);
2834 }
29353036 /** Sets the parameter type. */
+6
packages/openapi-ts/src/ts-dsl/decl/pattern.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeArray } from '../base';
···4243 spread(name: string): this {
4344 this._spread = name;
4445 return this;
4646+ }
4747+4848+ /** Walk this node and its children with a visitor. */
4949+ traverse(visitor: (node: SyntaxNode) => void): void {
5050+ console.log(visitor);
4551 }
46524753 /** Builds and returns a BindingName (ObjectBindingPattern, ArrayBindingPattern, or Identifier). */
+6
packages/openapi-ts/src/ts-dsl/decl/setter.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl } from '../base';
···2526 super();
2627 this.name = name;
2728 fn?.(this);
2929+ }
3030+3131+ /** Walk this node and its children with a visitor. */
3232+ traverse(visitor: (node: SyntaxNode) => void): void {
3333+ console.log(visitor);
2834 }
29353036 $render(): ts.SetAccessorDeclaration {
+6
packages/openapi-ts/src/ts-dsl/expr/array.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···4748 spread(expr: MaybeTsDsl<ts.Expression>): this {
4849 this._elements.push({ expr, kind: 'spread' });
4950 return this;
5151+ }
5252+5353+ /** Walk this node and its children with a visitor. */
5454+ traverse(visitor: (node: SyntaxNode) => void): void {
5555+ console.log(visitor);
5056 }
51575258 $render(): ts.ArrayLiteralExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/as.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl, TypeTsDsl } from '../base';
···1819 super();
1920 this.expr = expr;
2021 this.type = type;
2222+ }
2323+2424+ /** Walk this node and its children with a visitor. */
2525+ traverse(visitor: (node: SyntaxNode) => void): void {
2626+ console.log(visitor);
2127 }
22282329 $render() {
+6
packages/openapi-ts/src/ts-dsl/expr/attr.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { validTypescriptIdentifierRegExp } from '~/utils/regexp';
···2627 super();
2728 this.left = left;
2829 this.right = right;
3030+ }
3131+3232+ /** Walk this node and its children with a visitor. */
3333+ traverse(visitor: (node: SyntaxNode) => void): void {
3434+ console.log(visitor);
2935 }
30363137 $render(): ts.PropertyAccessExpression | ts.ElementAccessExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/await.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1213 constructor(expr: string | MaybeTsDsl<ts.Expression>) {
1314 super();
1415 this._awaitExpr = expr;
1616+ }
1717+1818+ /** Walk this node and its children with a visitor. */
1919+ traverse(visitor: (node: SyntaxNode) => void): void {
2020+ console.log(visitor);
1521 }
16221723 $render(): ts.AwaitExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/binary.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···117118 /** Multiplication — `this * expr` */
118119 times(expr: Expr): this {
119120 return this.opAndExpr('*', expr);
121121+ }
122122+123123+ /** Walk this node and its children with a visitor. */
124124+ traverse(visitor: (node: SyntaxNode) => void): void {
125125+ console.log(visitor);
120126 }
121127122128 $render(): ts.BinaryExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/call.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···2122 this.args(
2223 ...args.filter((a): a is NonNullable<typeof a> => a !== undefined),
2324 );
2525+ }
2626+2727+ /** Walk this node and its children with a visitor. */
2828+ traverse(visitor: (node: SyntaxNode) => void): void {
2929+ console.log(visitor);
2430 }
25312632 $render(): ts.CallExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/expr.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import type ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1516 constructor(id: string | MaybeTsDsl<ts.Expression>) {
1617 super();
1718 this._exprInput = id;
1919+ }
2020+2121+ /** Walk this node and its children with a visitor. */
2222+ traverse(visitor: (node: SyntaxNode) => void): void {
2323+ console.log(visitor);
1824 }
19252026 $render(): ts.Expression {
+6
packages/openapi-ts/src/ts-dsl/expr/id.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TsDsl } from '../base';
···89 constructor(name: string) {
910 super();
1011 this.name = name;
1212+ }
1313+1414+ /** Walk this node and its children with a visitor. */
1515+ traverse(visitor: (node: SyntaxNode) => void): void {
1616+ console.log(visitor);
1117 }
12181319 $render(): ts.Identifier {
+6
packages/openapi-ts/src/ts-dsl/expr/literal.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, @typescript-eslint/no-empty-object-type */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl } from '../base';
···1213 constructor(value: string | number | boolean | null) {
1314 super();
1415 this.value = value;
1616+ }
1717+1818+ /** Walk this node and its children with a visitor. */
1919+ traverse(visitor: (node: SyntaxNode) => void): void {
2020+ console.log(visitor);
1521 }
16221723 $render(): ts.LiteralTypeNode['literal'] {
+6
packages/openapi-ts/src/ts-dsl/expr/new.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1819 super();
1920 this.classExpr = classExpr;
2021 this.args(...args);
2222+ }
2323+2424+ /** Walk this node and its children with a visitor. */
2525+ traverse(visitor: (node: SyntaxNode) => void): void {
2626+ console.log(visitor);
2127 }
22282329 /** Builds the `NewExpression` node. */
+6
packages/openapi-ts/src/ts-dsl/expr/object.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···6970 spread(expr: ExprFn): this {
7071 this._props.push(new ObjectPropTsDsl({ kind: 'spread' }).value(expr));
7172 return this;
7373+ }
7474+7575+ /** Walk this node and its children with a visitor. */
7676+ traverse(visitor: (node: SyntaxNode) => void): void {
7777+ console.log(visitor);
7278 }
73797480 /** Builds and returns the object literal expression. */
+6
packages/openapi-ts/src/ts-dsl/expr/prefix.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···3839 op(op: ts.PrefixUnaryOperator): this {
3940 this._op = op;
4041 return this;
4242+ }
4343+4444+ /** Walk this node and its children with a visitor. */
4545+ traverse(visitor: (node: SyntaxNode) => void): void {
4646+ console.log(visitor);
4147 }
42484349 /** Renders the prefix unary expression node. */
+6
packages/openapi-ts/src/ts-dsl/expr/prop.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···3334 /** Returns true when all required builder calls are present. */
3435 get isValid(): boolean {
3536 return this.missingRequiredCalls().length === 0;
3737+ }
3838+3939+ /** Walk this node and its children with a visitor. */
4040+ traverse(visitor: (node: SyntaxNode) => void): void {
4141+ console.log(visitor);
3642 }
37433844 value(value: Expr | Stmt | ((p: ObjectPropTsDsl) => void)) {
+6
packages/openapi-ts/src/ts-dsl/expr/regexp.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TsDsl } from '../base';
···1819 super();
1920 this.pattern = pattern;
2021 this.flags = flags;
2222+ }
2323+2424+ /** Walk this node and its children with a visitor. */
2525+ traverse(visitor: (node: SyntaxNode) => void): void {
2626+ console.log(visitor);
2127 }
22282329 /** Emits a RegularExpressionLiteral node. */
+6
packages/openapi-ts/src/ts-dsl/expr/template.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···1617 add(value: string | MaybeTsDsl<ts.Expression>): this {
1718 this.parts.push(value);
1819 return this;
2020+ }
2121+2222+ /** Walk this node and its children with a visitor. */
2323+ traverse(visitor: (node: SyntaxNode) => void): void {
2424+ console.log(visitor);
1925 }
20262127 $render(): ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral {
+6
packages/openapi-ts/src/ts-dsl/expr/ternary.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···2627 otherwise(expr: string | MaybeTsDsl<ts.Expression>) {
2728 this._else = expr;
2829 return this;
3030+ }
3131+3232+ /** Walk this node and its children with a visitor. */
3333+ traverse(visitor: (node: SyntaxNode) => void): void {
3434+ console.log(visitor);
2935 }
30363137 $render(): ts.ConditionalExpression {
+6
packages/openapi-ts/src/ts-dsl/expr/typeof.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1314 constructor(expr: string | MaybeTsDsl<ts.Expression>) {
1415 super();
1516 this._expr = expr;
1717+ }
1818+1919+ /** Walk this node and its children with a visitor. */
2020+ traverse(visitor: (node: SyntaxNode) => void): void {
2121+ console.log(visitor);
1622 }
17231824 $render(): ts.TypeOfExpression {
+6
packages/openapi-ts/src/ts-dsl/layout/doc.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeArray } from '../base';
···5657 );
57585859 return node;
6060+ }
6161+6262+ /** Walk this node and its children with a visitor. */
6363+ traverse(visitor: (node: SyntaxNode) => void): void {
6464+ console.log(visitor);
5965 }
60666167 $render(): ts.Node {
+6
packages/openapi-ts/src/ts-dsl/layout/hint.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeArray } from '../base';
···3839 }
39404041 return node;
4242+ }
4343+4444+ /** Walk this node and its children with a visitor. */
4545+ traverse(visitor: (node: SyntaxNode) => void): void {
4646+ console.log(visitor);
4147 }
42484349 $render(): ts.Node {
+6
packages/openapi-ts/src/ts-dsl/layout/newline.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import type ts from 'typescript';
2334import { TsDsl } from '../base';
45import { IdTsDsl } from '../expr/id';
5667export class NewlineTsDsl extends TsDsl<ts.Identifier> {
88+ /** Walk this node and its children with a visitor. */
99+ traverse(visitor: (node: SyntaxNode) => void): void {
1010+ console.log(visitor);
1111+ }
1212+713 $render(): ts.Identifier {
814 return this.$node(new IdTsDsl('\n'));
915 }
+6
packages/openapi-ts/src/ts-dsl/layout/note.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeArray } from '../base';
···3637 );
37383839 return node;
4040+ }
4141+4242+ /** Walk this node and its children with a visitor. */
4343+ traverse(visitor: (node: SyntaxNode) => void): void {
4444+ console.log(visitor);
3945 }
40464147 $render(): ts.Node {
···44import { TsDsl } from '../base';
55import { TypeParamTsDsl } from '../type/param';
6677-export class TypeParamsMixin extends TsDsl {
77+export abstract class TypeParamsMixin extends TsDsl {
88 protected _generics?: Array<string | MaybeTsDsl<TypeParamTsDsl>>;
991010 /** Adds a single type parameter (e.g. `T` in `Array<T>`). */
···2828 const node = typeof g === 'string' ? new TypeParamTsDsl(g) : g;
2929 return this.$node(node);
3030 });
3131- }
3232-3333- $render(): ts.Node {
3434- throw new Error('noop');
3531 }
3632}
+1-5
packages/openapi-ts/src/ts-dsl/mixins/value.ts
···33import type { MaybeTsDsl } from '../base';
44import { TsDsl } from '../base';
5566-export class ValueMixin extends TsDsl {
66+export abstract class ValueMixin extends TsDsl {
77 protected value?: string | MaybeTsDsl<ts.Expression>;
8899 /** Sets the initializer expression (e.g. `= expr`). */
···14141515 protected $value(): ts.Expression | undefined {
1616 return this.$node(this.value);
1717- }
1818-1919- $render(): ts.Node {
2020- throw new Error('noop');
2117 }
2218}
+6
packages/openapi-ts/src/ts-dsl/stmt/if.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···2324 otherwise(...statements: ReadonlyArray<MaybeTsDsl<ts.Statement>>): this {
2425 this._else = statements;
2526 return this;
2727+ }
2828+2929+ /** Walk this node and its children with a visitor. */
3030+ traverse(visitor: (node: SyntaxNode) => void): void {
3131+ console.log(visitor);
2632 }
27332834 $render(): ts.IfStatement {
+6
packages/openapi-ts/src/ts-dsl/stmt/return.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1213 constructor(expr?: string | MaybeTsDsl<ts.Expression>) {
1314 super();
1415 this._returnExpr = expr;
1616+ }
1717+1818+ /** Walk this node and its children with a visitor. */
1919+ traverse(visitor: (node: SyntaxNode) => void): void {
2020+ console.log(visitor);
1521 }
16221723 $render(): ts.ReturnStatement {
+6
packages/openapi-ts/src/ts-dsl/stmt/stmt.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TsDsl } from '../base';
···89 constructor(inner: ts.Expression | ts.Statement | TsDsl<any>) {
910 super();
1011 this._inner = inner;
1212+ }
1313+1414+ /** Walk this node and its children with a visitor. */
1515+ traverse(visitor: (node: SyntaxNode) => void): void {
1616+ console.log(visitor);
1117 }
12181319 $render(): ts.Statement {
+6
packages/openapi-ts/src/ts-dsl/stmt/throw.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···1819 message(value: string | MaybeTsDsl<ts.Expression>): this {
1920 this.msg = value;
2021 return this;
2222+ }
2323+2424+ /** Walk this node and its children with a visitor. */
2525+ traverse(visitor: (node: SyntaxNode) => void): void {
2626+ console.log(visitor);
2127 }
22282329 $render(): ts.ThrowStatement {
+17-2
packages/openapi-ts/src/ts-dsl/stmt/var.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···2021 protected name?: string;
2122 protected _type?: TypeTsDsl;
22232323- constructor(name?: string) {
2424+ constructor(name?: Symbol | string) {
2425 super();
2525- this.name = name;
2626+ if (name) {
2727+ if (typeof name === 'string') {
2828+ this.name = name;
2929+ } else {
3030+ this.name = name.finalName;
3131+ this.symbol = name;
3232+ this.symbol.setKind('var');
3333+ this.symbol.setRootNode(this);
3434+ }
3535+ }
2636 }
27372838 const(): this {
···3343 let(): this {
3444 this.kind = ts.NodeFlags.Let;
3545 return this;
4646+ }
4747+4848+ /** Walk this node and its children with a visitor. */
4949+ traverse(visitor: (node: SyntaxNode) => void): void {
5050+ console.log(visitor);
3651 }
37523853 /** Sets the variable type. */
+6
packages/openapi-ts/src/ts-dsl/token.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TsDsl } from './base';
···5354 return (this as TokenTsDsl<ts.SyntaxKind.DotDotDotToken>).kind(
5455 ts.SyntaxKind.DotDotDotToken,
5556 );
5757+ }
5858+5959+ /** Walk this node and its children with a visitor. */
6060+ traverse(visitor: (node: SyntaxNode) => void): void {
6161+ console.log(visitor);
5662 }
57635864 /** Renders the final token */
+16-3
packages/openapi-ts/src/ts-dsl/type/alias.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···910import { TypeParamsMixin } from '../mixins/type-params';
10111112export class TypeAliasTsDsl extends TsDsl<ts.TypeAliasDeclaration> {
1212- protected value?: MaybeTsDsl<ts.TypeNode>;
1313 protected modifiers = createModifierAccessor(this);
1414 protected name: string;
1515+ protected value?: MaybeTsDsl<ts.TypeNode>;
15161616- constructor(name: string, fn?: (t: TypeAliasTsDsl) => void) {
1717+ constructor(name: Symbol | string, fn?: (t: TypeAliasTsDsl) => void) {
1718 super();
1818- this.name = name;
1919+ if (typeof name === 'string') {
2020+ this.name = name;
2121+ } else {
2222+ this.name = name.finalName;
2323+ this.symbol = name;
2424+ this.symbol.setKind('type');
2525+ this.symbol.setRootNode(this);
2626+ }
1927 fn?.(this);
2828+ }
2929+3030+ /** Walk this node and its children with a visitor. */
3131+ traverse(visitor: (node: SyntaxNode) => void): void {
3232+ console.log(visitor);
2033 }
21342235 /** Sets the type expression on the right-hand side of `= ...`. */
+6
packages/openapi-ts/src/ts-dsl/type/and.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TypeTsDsl } from '../base';
···89 constructor(...nodes: Array<string | ts.TypeNode | TypeTsDsl>) {
910 super();
1011 this.types(...nodes);
1212+ }
1313+1414+ /** Walk this node and its children with a visitor. */
1515+ traverse(visitor: (node: SyntaxNode) => void): void {
1616+ console.log(visitor);
1117 }
12181319 types(...nodes: Array<string | ts.TypeNode | TypeTsDsl>): this {
+21-9
packages/openapi-ts/src/ts-dsl/type/attr.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···78import { TypeExprMixin } from '../mixins/type-expr';
89910export class TypeAttrTsDsl extends TypeTsDsl<ts.QualifiedName> {
1010- protected _base?: string | MaybeTsDsl<ts.EntityName>;
1111- protected right: string | ts.Identifier;
1111+ protected _base?: Symbol | string | MaybeTsDsl<ts.EntityName>;
1212+ protected right: Symbol | string | ts.Identifier;
12131314 constructor(
1414- base: string | MaybeTsDsl<ts.EntityName>,
1515+ base: Symbol | string | MaybeTsDsl<ts.EntityName>,
1516 right: string | ts.Identifier,
1617 );
1717- constructor(right: string | ts.Identifier);
1818+ constructor(right: Symbol | string | ts.Identifier);
1819 constructor(
1919- baseOrRight: string | MaybeTsDsl<ts.EntityName>,
2020- maybeRight?: string | ts.Identifier,
2020+ baseOrRight: Symbol | string | MaybeTsDsl<ts.EntityName>,
2121+ maybeRight?: Symbol | string | ts.Identifier,
2122 ) {
2223 super();
2324 if (maybeRight) {
···2930 }
3031 }
31323232- base(base?: string | MaybeTsDsl<ts.EntityName>): this {
3333+ base(base?: Symbol | string | MaybeTsDsl<ts.EntityName>): this {
3334 this._base = base;
3435 return this;
3536 }
36373838+ /** Walk this node and its children with a visitor. */
3939+ traverse(visitor: (node: SyntaxNode) => void): void {
4040+ console.log(visitor);
4141+ }
4242+3743 $render(): ts.QualifiedName {
3844 if (!this._base) {
3945 throw new Error('TypeAttrTsDsl: missing base for qualified name');
4046 }
4141- const left = this.$node(this._base);
4747+ const left =
4848+ typeof this._base !== 'string' && this._base && 'id' in this._base
4949+ ? this.$node(this._base.finalName)
5050+ : this.$node(this._base);
4251 if (!ts.isEntityName(left)) {
4352 throw new Error('TypeAttrTsDsl: base must be an EntityName');
4453 }
4545- const right = this.$maybeId(this.right);
5454+ const right =
5555+ typeof this.right !== 'string' && this.right && 'id' in this.right
5656+ ? this.$maybeId(this.right.finalName)
5757+ : this.$maybeId(this.right);
4658 return ts.factory.createQualifiedName(left, right);
4759 }
4860}
+29-12
packages/openapi-ts/src/ts-dsl/type/expr.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TypeTsDsl } from '../base';
···1112import { TypeAttrTsDsl } from './attr';
12131314export class TypeExprTsDsl extends TypeTsDsl<ts.TypeReferenceNode> {
1414- protected _exprInput?: string | ts.Identifier | TypeAttrTsDsl;
1515+ protected _exprInput?: Symbol | string | TypeAttrTsDsl;
15161617 constructor();
1718 constructor(fn: (t: TypeExprTsDsl) => void);
1818- constructor(name: string);
1919- constructor(name: string, fn?: (t: TypeExprTsDsl) => void);
1919+ constructor(name: Symbol | string);
2020+ constructor(name: Symbol | string, fn?: (t: TypeExprTsDsl) => void);
2021 constructor(
2121- nameOrFn?: string | ((t: TypeExprTsDsl) => void),
2222+ name?: Symbol | string | ((t: TypeExprTsDsl) => void),
2223 fn?: (t: TypeExprTsDsl) => void,
2324 ) {
2425 super();
2525- if (typeof nameOrFn === 'string') {
2626- this._exprInput = nameOrFn;
2727- fn?.(this);
2828- } else {
2929- nameOrFn?.(this);
2626+ if (name) {
2727+ if (typeof name === 'function') {
2828+ name(this);
2929+ } else {
3030+ this._exprInput = name;
3131+ if (typeof name !== 'string') {
3232+ const symbol = this.getRootSymbol();
3333+ if (symbol) symbol.addDependency(name);
3434+ }
3535+ fn?.(this);
3636+ }
3037 }
3138 }
3239···3643 right instanceof TypeAttrTsDsl
3744 ? right.base(this._exprInput)
3845 : new TypeAttrTsDsl(this._exprInput!, right);
4646+ this._exprInput = this._exprInput.setParent(this);
3947 return this;
4848+ }
4949+5050+ /** Walk this node and its children with a visitor. */
5151+ traverse(visitor: (node: SyntaxNode) => void): void {
5252+ console.log(visitor);
4053 }
41544255 $render(): ts.TypeReferenceNode {
4343- if (!this._exprInput)
4444- throw new Error('TypeExpr must have either an expression or an object');
5656+ if (!this._exprInput) throw new Error('TypeExpr must have an expression');
5757+ const typeName =
5858+ typeof this._exprInput === 'string' ||
5959+ this._exprInput instanceof TypeAttrTsDsl
6060+ ? this.$type(this._exprInput)
6161+ : this._exprInput.finalName;
4562 return ts.factory.createTypeReferenceNode(
4663 // @ts-expect-error --- need to fix types
4747- this.$type(this._exprInput),
6464+ typeName,
4865 this.$generics(),
4966 );
5067 }
+6
packages/openapi-ts/src/ts-dsl/type/func.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TypeTsDsl } from '../base';
···1516 returns(type: string | TypeTsDsl): this {
1617 this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
1718 return this;
1919+ }
2020+2121+ /** Walk this node and its children with a visitor. */
2222+ traverse(visitor: (node: SyntaxNode) => void): void {
2323+ console.log(visitor);
1824 }
19252026 $render(): ts.FunctionTypeNode {
+6
packages/openapi-ts/src/ts-dsl/type/idx-sig.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···3031 key(type: Type): this {
3132 this._key = type;
3233 return this;
3434+ }
3535+3636+ /** Walk this node and its children with a visitor. */
3737+ traverse(visitor: (node: SyntaxNode) => void): void {
3838+ console.log(visitor);
3339 }
34403541 /** Sets the property type. */
+6
packages/openapi-ts/src/ts-dsl/type/idx.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···3031 index(index: string | MaybeTsDsl<ts.TypeNode> | number): this {
3132 this._index = index;
3233 return this;
3434+ }
3535+3636+ /** Walk this node and its children with a visitor. */
3737+ traverse(visitor: (node: SyntaxNode) => void): void {
3838+ console.log(visitor);
3339 }
34403541 $render(): ts.IndexedAccessTypeNode {
+6
packages/openapi-ts/src/ts-dsl/type/literal.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TypeTsDsl } from '../base';
···910 constructor(value: string | number | boolean | null) {
1011 super();
1112 this.value = value;
1313+ }
1414+1515+ /** Walk this node and its children with a visitor. */
1616+ traverse(visitor: (node: SyntaxNode) => void): void {
1717+ console.log(visitor);
1218 }
13191420 $render(): ts.LiteralTypeNode {
+6
packages/openapi-ts/src/ts-dsl/type/mapped.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···6364 required(): this {
6465 this.questionToken = new TokenTsDsl().minus();
6566 return this;
6767+ }
6868+6969+ /** Walk this node and its children with a visitor. */
7070+ traverse(visitor: (node: SyntaxNode) => void): void {
7171+ console.log(visitor);
6672 }
67736874 /** Sets the mapped value type: `[K in X]: ValueType` */
+6
packages/openapi-ts/src/ts-dsl/type/object.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TypeTsDsl } from '../base';
···2930 const prop = new TypePropTsDsl(name, fn);
3031 this.props.push(prop);
3132 return this;
3333+ }
3434+3535+ /** Walk this node and its children with a visitor. */
3636+ traverse(visitor: (node: SyntaxNode) => void): void {
3737+ console.log(visitor);
3238 }
33393440 $render(): ts.TypeNode {
+6
packages/openapi-ts/src/ts-dsl/type/operator.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···4445 this.operator(ts.SyntaxKind.ReadonlyKeyword);
4546 this.type(type);
4647 return this;
4848+ }
4949+5050+ /** Walk this node and its children with a visitor. */
5151+ traverse(visitor: (node: SyntaxNode) => void): void {
5252+ console.log(visitor);
4753 }
48544955 /** Sets the target type of the operator. */
+6
packages/openapi-ts/src/ts-dsl/type/or.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TypeTsDsl } from '../base';
···89 constructor(...nodes: Array<string | ts.TypeNode | TypeTsDsl>) {
910 super();
1011 this.types(...nodes);
1212+ }
1313+1414+ /** Walk this node and its children with a visitor. */
1515+ traverse(visitor: (node: SyntaxNode) => void): void {
1616+ console.log(visitor);
1117 }
12181319 types(...nodes: Array<string | ts.TypeNode | TypeTsDsl>): this {
+6
packages/openapi-ts/src/ts-dsl/type/param.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···2526 extends(constraint: string | MaybeTsDsl<TypeTsDsl> | boolean): this {
2627 this.constraint = constraint;
2728 return this;
2929+ }
3030+3131+ /** Walk this node and its children with a visitor. */
3232+ traverse(visitor: (node: SyntaxNode) => void): void {
3333+ console.log(visitor);
2834 }
29353036 $render(): ts.TypeParameterDeclaration {
+6
packages/openapi-ts/src/ts-dsl/type/prop.ts
···11/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1920 super();
2021 this.name = name;
2122 fn(this);
2323+ }
2424+2525+ /** Walk this node and its children with a visitor. */
2626+ traverse(visitor: (node: SyntaxNode) => void): void {
2727+ console.log(visitor);
2228 }
23292430 /** Sets the property type. */
+6
packages/openapi-ts/src/ts-dsl/type/query.ts
···11/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
22+import type { SyntaxNode } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
···1516 constructor(expr: string | MaybeTsDsl<TypeTsDsl | ts.Expression>) {
1617 super();
1718 this._expr = expr;
1919+ }
2020+2121+ /** Walk this node and its children with a visitor. */
2222+ traverse(visitor: (node: SyntaxNode) => void): void {
2323+ console.log(visitor);
1824 }
19252026 $render(): ts.TypeQueryNode {
+6
packages/openapi-ts/src/ts-dsl/type/template.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
···1516 add(part: string | MaybeTsDsl<ts.TypeNode>): this {
1617 this.parts.push(part);
1718 return this;
1919+ }
2020+2121+ /** Walk this node and its children with a visitor. */
2222+ traverse(visitor: (node: SyntaxNode) => void): void {
2323+ console.log(visitor);
1824 }
19252026 /** Renders a TemplateLiteralTypeNode. */
+6
packages/openapi-ts/src/ts-dsl/type/tuple.ts
···11+import type { SyntaxNode } from '@hey-api/codegen-core';
12import ts from 'typescript';
2334import { TypeTsDsl } from '../base';
···1314 elements(...types: Array<string | ts.TypeNode | TypeTsDsl>): this {
1415 this._elements.push(...types);
1516 return this;
1717+ }
1818+1919+ /** Walk this node and its children with a visitor. */
2020+ traverse(visitor: (node: SyntaxNode) => void): void {
2121+ console.log(visitor);
1622 }
17231824 $render(): ts.TupleTypeNode {