···11+MIT License
22+33+Copyright (c) Hey API
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is
1010+furnished to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121+SOFTWARE.
+126
packages/codegen-core/README.md
···11+<div align="center">
22+ <img alt="Three people building a brick structure" height="214" src="https://heyapi.dev/images/bricks-640w.png" width="320">
33+ <h1 align="center"><b>Codegen Core</b></h1>
44+ <p align="center">🧱 TypeScript framework for generating structured, multi-file source code from abstract syntax trees.</p>
55+</div>
66+77+<br/>
88+99+<p align="center">
1010+ <a href="https://opensource.org/license/mit" rel="nofollow"><img src="https://img.shields.io/github/license/hey-api/openapi-ts" alt="MIT License"></a>
1111+ <a href="https://github.com/hey-api/openapi-ts/actions?query=branch%3Amain"><img src="https://github.com/hey-api/openapi-ts/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
1212+</p>
1313+1414+<p align="center">
1515+ <a href="https://github.com/hey-api/openapi-ts/issues">Issues</a>
1616+ <span> • </span>
1717+ <a href="https://heyapi.dev/openapi-ts/community/contributing">Contribute</a>
1818+ <span> • </span>
1919+ <a href="https://heyapi.dev/openapi-ts/community/spotlight#core-team">Join Core Team</a>
2020+</p>
2121+2222+<br/>
2323+2424+## Dashboard
2525+2626+Hey API is an ecosystem of products helping you build better APIs. Superpower your codegen and APIs with Hey API Platform.
2727+2828+[Sign In](https://app.heyapi.dev) to Hey API Platform.
2929+3030+## Contributing
3131+3232+Want to see your code in products used by millions?
3333+3434+Start with our [Contributing](https://heyapi.dev/openapi-ts/community/contributing) guide and release your first feature.
3535+3636+## Sponsors
3737+3838+Help Hey API stay around for the long haul by becoming a [sponsor](https://github.com/sponsors/hey-api).
3939+4040+<h3 align="center">Gold</h3>
4141+4242+<table align="center" style="justify-content: center;align-items: center;display: flex;">
4343+ <tbody>
4444+ <tr>
4545+ <td align="center">
4646+ <p></p>
4747+ <p>
4848+ <a href="https://kutt.it/pkEZyc" target="_blank">
4949+ <picture height="50px">
5050+ <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/images/stainless-logo-wordmark-480w.jpeg">
5151+ <img alt="Stainless logo" height="50px" src="https://heyapi.dev/images/stainless-logo-wordmark-480w.jpeg">
5252+ </picture>
5353+ </a>
5454+ <br/>
5555+ Best-in-class SDKs and MCP for your API.
5656+ <br/>
5757+ <a href="https://kutt.it/pkEZyc" style="text-decoration:none;" target="_blank">
5858+ stainless.com
5959+ </a>
6060+ </p>
6161+ <p></p>
6262+ </td>
6363+ </tr>
6464+ </tbody>
6565+</table>
6666+6767+<h3 align="center">Silver</h3>
6868+6969+<table align="center" style="justify-content: center;align-items: center;display: flex;">
7070+ <tbody>
7171+ <tr>
7272+ <td align="center">
7373+ <a href="https://kutt.it/skQUVd" target="_blank">
7474+ <picture height="40px">
7575+ <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/images/scalar-logo-wordmark-480w.jpeg">
7676+ <img alt="Scalar logo" height="40px" src="https://heyapi.dev/scalar-logo-wordmark.svg">
7777+ </picture>
7878+ </a>
7979+ <br/>
8080+ <a href="https://kutt.it/skQUVd" style="text-decoration:none;" target="_blank">
8181+ scalar.com
8282+ </a>
8383+ </td>
8484+ <td align="center">
8585+ <a href="https://kutt.it/Dr9GuW" target="_blank">
8686+ <picture height="40px">
8787+ <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/fastapi-logo-wordmark.svg">
8888+ </picture>
8989+ </a>
9090+ <br/>
9191+ <a href="https://kutt.it/Dr9GuW" style="text-decoration:none;" target="_blank">
9292+ fastapi.tiangolo.com
9393+ </a>
9494+ </td>
9595+ </tr>
9696+ </tbody>
9797+</table>
9898+9999+<h3 align="center">Bronze</h3>
100100+101101+<table align="center" style="justify-content: center;align-items: center;display: flex;">
102102+ <tbody>
103103+ <tr>
104104+ <td align="center">
105105+ <a href="https://kutt.it/YpaKsX" target="_blank">
106106+ <picture height="34px">
107107+ <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/images/kinde-logo-wordmark-dark-480w.webp">
108108+ <img alt="Kinde logo" height="34px" src="https://heyapi.dev/images/kinde-logo-wordmark-480w.jpeg">
109109+ </picture>
110110+ </a>
111111+ </td>
112112+ <td align="center">
113113+ <a href="https://kutt.it/KkqSaw" target="_blank">
114114+ <picture height="34px">
115115+ <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/images/cella-logo-wordmark-480w.webp">
116116+ <img alt="Cella logo" height="34px" src="https://heyapi.dev/cella-logo-wordmark.svg">
117117+ </picture>
118118+ </a>
119119+ </td>
120120+ </tr>
121121+ </tbody>
122122+</table>
123123+124124+## License
125125+126126+Released under the [MIT License](https://github.com/hey-api/openapi-ts/blob/main/LICENSE.md).
···11+import type { ICodegenImport } from '../imports/types';
22+import type { ICodegenRenderer } from '../renderers/types';
33+import type { ICodegenSymbol } from '../symbols/types';
44+55+export interface ICodegenFile {
66+ /**
77+ * Adds an export to this file.
88+ *
99+ * This is also known as a re-export.
1010+ *
1111+ * @param exp The export to add
1212+ */
1313+ addExport(exp: ICodegenImport): void;
1414+ /**
1515+ * Adds an import to this file.
1616+ *
1717+ * @param imp The import to add
1818+ */
1919+ addImport(imp: ICodegenImport): void;
2020+ /**
2121+ * Adds a symbol defined by this file.
2222+ *
2323+ * @param symbol The symbol to add
2424+ */
2525+ addSymbol(symbol: ICodegenSymbol): void;
2626+ /**
2727+ * Symbols exported from other files.
2828+ **/
2929+ exports: ReadonlyArray<ICodegenImport>;
3030+ /**
3131+ * Returns all symbols used in this file (declared + imported).
3232+ *
3333+ * @returns List of all symbols used in this file
3434+ */
3535+ getAllSymbols(): ReadonlyArray<ICodegenSymbol>;
3636+ /**
3737+ * Checks if this file contains any content.
3838+ *
3939+ * This is used to determine whether we want to process the file further.
4040+ * By default, we consider only symbols and exports as content.
4141+ *
4242+ * @returns True if the file contains content
4343+ */
4444+ hasContent(): boolean;
4545+ /**
4646+ * Checks if this file defines a symbol with the given name.
4747+ *
4848+ * @param name Symbol name to check
4949+ * @returns True if the symbol is defined by this file
5050+ */
5151+ hasSymbol(name: string): boolean;
5252+ /**
5353+ * Symbols imported from other files.
5454+ **/
5555+ imports: ReadonlyArray<ICodegenImport>;
5656+ /**
5757+ * Optional metadata about the file.
5858+ **/
5959+ meta: {
6060+ /**
6161+ * Optional file extension.
6262+ *
6363+ * @example ".ts"
6464+ */
6565+ extension?: '.ts' | (string & {});
6666+ /**
6767+ * Optional logical module or package name.
6868+ *
6969+ * @example "models.user"
7070+ */
7171+ moduleName?: string;
7272+ /**
7373+ * Optional path transformer.
7474+ *
7575+ * @param path Original file path passed to the constructor.
7676+ */
7777+ path?: ((path: string) => string) | string;
7878+ /**
7979+ * Renderer ID.
8080+ *
8181+ * @example "typescript"
8282+ */
8383+ renderer?: ICodegenRenderer['id'];
8484+ };
8585+ /**
8686+ * Logical output path (used for writing the file).
8787+ *
8888+ * @example "models/user.ts"
8989+ */
9090+ path: string;
9191+ /**
9292+ * Returns a relative path to this file from another file.
9393+ *
9494+ * @param file The file from which we want the relative path to this file.
9595+ * @example "./this-file.ts"
9696+ */
9797+ relativePathFromFile(file: Pick<ICodegenFile, 'path'>): string;
9898+ /**
9999+ * Returns a relative path to file from this file.
100100+ *
101101+ * @param file The file to which we want the relative path.
102102+ * @example "./another-file.ts"
103103+ */
104104+ relativePathToFile(file: Pick<ICodegenFile, 'path'>): string;
105105+ /**
106106+ * Top-level symbols declared in this file.
107107+ **/
108108+ symbols: ReadonlyArray<ICodegenSymbol>;
109109+}
+64
packages/codegen-core/src/imports/types.d.ts
···11+import type { ICodegenFile } from '../files/types';
22+33+export interface ICodegenImport {
44+ /**
55+ * Optional aliasing map for imported symbols.
66+ *
77+ * Keys must be a subset of `names`, values are aliases.
88+ *
99+ * @example { User: "ImportedUser" }
1010+ */
1111+ aliases?: Record<string, string>;
1212+ /**
1313+ * Name of the default import, if any.
1414+ *
1515+ * @example "React"
1616+ */
1717+ defaultImport?: string;
1818+ /**
1919+ * Source file or external module from which symbols are imported.
2020+ *
2121+ * For internal files, this should be a ICodegenFile instance to enable
2222+ * dynamic path computation. For external or system modules, use a string.
2323+ *
2424+ * @example "./models/user"
2525+ * @example "node:path"
2626+ */
2727+ from: ICodegenFile | string;
2828+ /**
2929+ * Names of the symbols imported from the source.
3030+ *
3131+ * Must be non-empty unless `isNamespaceImport` is true.
3232+ * All imported names, regardless of whether they are used as types or values.
3333+ *
3434+ * @example ["User", "UserDTO"]
3535+ */
3636+ names?: ReadonlyArray<string>;
3737+ /**
3838+ * If this import is a namespace import (e.g. `import * as ns from "..."`),
3939+ * this should be the namespace alias. Set to `true` if no alias is needed.
4040+ *
4141+ * @example "utils"
4242+ * @example true
4343+ */
4444+ namespaceImport?: boolean | string;
4545+ /**
4646+ * Whether the default import is type-only.
4747+ *
4848+ * @example true
4949+ */
5050+ typeDefaultImport?: boolean;
5151+ /**
5252+ * Subset of `names` that are imported using the `type` modifier.
5353+ * These symbols will be emitted as type-only imports in TypeScript.
5454+ *
5555+ * @example ["UserDTO"]
5656+ */
5757+ typeNames?: ReadonlyArray<string>;
5858+ /**
5959+ * Whether the namespace import is type-only.
6060+ *
6161+ * @example true
6262+ */
6363+ typeNamespaceImport?: boolean;
6464+}
+9
packages/codegen-core/src/index.ts
···11+export { CodegenFile } from './files/file';
22+export type { ICodegenFile } from './files/types';
33+export type { ICodegenImport } from './imports/types';
44+export type { ICodegenMeta } from './meta/types';
55+export type { ICodegenOutput } from './output/types';
66+export { CodegenProject } from './project/project';
77+export type { ICodegenProject } from './project/types';
88+export type { ICodegenRenderer } from './renderers/types';
99+export type { ICodegenSymbol } from './symbols/types';
+8
packages/codegen-core/src/meta/types.d.ts
···11+/**
22+ * Arbitrary metadata passed to render functions.
33+ *
44+ * Implementors should extend this interface for their own needs.
55+ */
66+export interface ICodegenMeta {
77+ [key: string]: unknown;
88+}
+23
packages/codegen-core/src/output/types.d.ts
···11+export interface ICodegenOutput {
22+ /**
33+ * The main content of the file to output.
44+ *
55+ * A raw string representing source code.
66+ *
77+ * @example "function foo(): void {\n // implementation\n}\n"
88+ */
99+ content: string;
1010+ /**
1111+ * Optional metadata or hints for the emitter, such as formatting options,
1212+ * source maps, or language-specific flags.
1313+ *
1414+ * @example { format: "prettier", sourceMap: true }
1515+ */
1616+ meta: Record<string, unknown>;
1717+ /**
1818+ * Logical output path (used for writing the file).
1919+ *
2020+ * @example "models/user.ts"
2121+ */
2222+ path: string;
2323+}
···11+import type { ICodegenFile } from '../files/types';
22+import type { ICodegenImport } from '../imports/types';
33+import type { ICodegenMeta } from '../meta/types';
44+import type { ICodegenOutput } from '../output/types';
55+import type { ICodegenRenderer } from '../renderers/types';
66+import type { ICodegenSymbol } from '../symbols/types';
77+88+/**
99+ * Represents a code generation project consisting of multiple codegen files.
1010+ * Manages imports, symbols, and output generation across the project.
1111+ */
1212+export interface ICodegenProject {
1313+ /**
1414+ * Adds an export declaration to a specific file, creating the file if it doesn't exist.
1515+ *
1616+ * @param fileOrPath - File instance or file path where to add the export.
1717+ * @param imp - The export declaration to add.
1818+ * @example
1919+ * project.addExportToFile("models/user.ts", { from: "lib", names: ["User"] });
2020+ */
2121+ addExportToFile(fileOrPath: ICodegenFile | string, imp: ICodegenImport): void;
2222+ /**
2323+ * Adds an import declaration to a specific file, creating the file if it doesn't exist.
2424+ *
2525+ * @param fileOrPath - File instance or file path where to add the import.
2626+ * @param imp - The import declaration to add.
2727+ * @example
2828+ * project.addImportToFile("models/user.ts", { from: "lib", names: ["User"] });
2929+ */
3030+ addImportToFile(fileOrPath: ICodegenFile | string, imp: ICodegenImport): void;
3131+ /**
3232+ * Adds a symbol to a specific file, creating the file if it doesn't exist.
3333+ *
3434+ * @param fileOrPath - File instance or file path where to add the symbol.
3535+ * @param symbol - The symbol to add.
3636+ * @example
3737+ * project.addSymbolToFile("models/user.ts", { name: "User", value: tsNode });
3838+ */
3939+ addSymbolToFile(
4040+ fileOrPath: ICodegenFile | string,
4141+ symbol: ICodegenSymbol,
4242+ ): void;
4343+ /**
4444+ * Creates a new codegen file with optional metadata and adds it to the project.
4545+ *
4646+ * If a file with the same path already exists, it is returned instead.
4747+ *
4848+ * @param path - The logical output path for the file (e.g. "models/user.ts").
4949+ * @param meta - Optional renderer and metadata to attach to the file (e.g. { isInternal: true }).
5050+ * @returns The newly created file instance.
5151+ * @example
5252+ * const file = project.createFile("models/user.ts", { isInternal: true });
5353+ */
5454+ createFile(
5555+ path: string,
5656+ meta?: ICodegenFile['meta'] & { renderer?: ICodegenRenderer },
5757+ ): ICodegenFile;
5858+ /**
5959+ * Ensures a codegen file exists and returns it.
6060+ *
6161+ * If a file does not exist yet, it is created with minimal information.
6262+ * Later, it is expected `createFile()` will be called which will fill in
6363+ * the missing information such as optional metadata.
6464+ *
6565+ * @param fileOrPath - The logical output path for the file or the file itself.
6666+ * @returns The file instance.
6767+ * @example
6868+ * const file = project.ensureFile("models/user.ts");
6969+ */
7070+ ensureFile(fileOrPath: ICodegenFile | string): ICodegenFile;
7171+ /**
7272+ * Returns all files in the project in insertion order.
7373+ *
7474+ * @example
7575+ * project.files.forEach(file => console.log(file.path));
7676+ */
7777+ readonly files: ReadonlyArray<ICodegenFile>;
7878+ /**
7979+ * Returns all symbols declared or imported across all files.
8080+ *
8181+ * @returns Flattened list of all codegen symbols.
8282+ * @example
8383+ * project.getAllSymbols().filter(s => s.name === "User");
8484+ */
8585+ getAllSymbols(): ReadonlyArray<ICodegenSymbol>;
8686+ /**
8787+ * Retrieves a file by its logical output path.
8888+ *
8989+ * @param path - The file path to find.
9090+ * @returns The file if found, or undefined otherwise.
9191+ * @example
9292+ * const file = project.getFileByPath("models/user.ts");
9393+ */
9494+ getFileByPath(path: string): ICodegenFile | undefined;
9595+ /**
9696+ * Produces output representations for all files in the project.
9797+ *
9898+ * @param meta Arbitrary metadata.
9999+ * @returns Array of outputs ready for writing or further processing.
100100+ * @example
101101+ * project.render().forEach(output => writeFile(output));
102102+ */
103103+ render(meta?: ICodegenMeta): ReadonlyArray<ICodegenOutput>;
104104+}
+24
packages/codegen-core/src/renderers/types.d.ts
···11+import type { CodegenFile } from '../files/file';
22+import type { ICodegenMeta } from '../meta/types';
33+import type { ICodegenOutput } from '../output/types';
44+55+export interface ICodegenRenderer {
66+ /**
77+ * Optional: hook for renderer-level setup logic (e.g., formatting, config)
88+ */
99+ configure?(options: Record<string, unknown>): void;
1010+ /**
1111+ * Unique identifier for this renderer.
1212+ *
1313+ * @example "typescript"
1414+ */
1515+ id: string;
1616+ /**
1717+ * Returns printable data.
1818+ *
1919+ * @param file The file to render.
2020+ * @param meta Arbitrary metadata.
2121+ * @returns Output for file emit step
2222+ */
2323+ render(file: CodegenFile, meta?: ICodegenMeta): ICodegenOutput;
2424+}
+25
packages/codegen-core/src/symbols/types.d.ts
···11+export interface ICodegenSymbol {
22+ /**
33+ * Optional description or doc comment.
44+ *
55+ * @example "Represents a user in the system"
66+ */
77+ description?: string;
88+ /**
99+ * Optional kind of symbol (e.g. "class", "function", "type", etc.).
1010+ *
1111+ * @example "class"
1212+ */
1313+ kind?: string;
1414+ /**
1515+ * Unique identifier for the symbol within its file.
1616+ *
1717+ * @example "UserModel"
1818+ */
1919+ name: string;
2020+ /**
2121+ * Internal representation of the symbol (e.g. AST node, IR object, raw
2222+ * code). Used to generate output.
2323+ */
2424+ value?: unknown;
2525+}