Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Connect AI assistants like Claude Code, Cursor, and Windsurf to The Codegen Proj








2 changes: 2 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ Prefix that follows specification is not enough though. Remember that the title








66 changes: 66 additions & 0 deletions docs/generators/profiles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
sidebar_position: 1
---

# 🎯 Profiles (OpenAPI)

Profiles are high-level sugar for OpenAPI inputs that expand into the granular
generators tuned for **REST consumers**: plain TypeScript `interface` models with
**no** `marshal`/`unmarshal`/`validate` ceremony, plus standalone serializer
functions and an optional fetch client. They are the idiomatic shape expected by
tools like `openapi-typescript`, `orval`, `kubb` and `heyapi`.

```js
export default {
inputType: 'openapi',
inputPath: './openapi.json',
language: 'typescript',
profile: 'client', // or 'types'
generators: [] // optional explicit generators are appended as overrides
};
```

## Available profiles

| Profile | Expands into | Emits a client? |
|----------|--------------|-----------------|
| `types` | interface `payloads` + interface `parameters` (with standalone serializers) + `headers` | No |
| `client` | everything in `types` **plus** `channels` (`http_client`) + `client` (`http`) | Yes |

### `types`

Generates the data model surface only — one plain interface per payload,
parameter set and header group. Parameter models come with free functions
(`serialize<Name>QueryParameters`, `serialize<Name>Url`) that carry the OpenAPI
style/explode logic, so you can build URLs without instantiating a class.

### `client`

Everything in `types`, plus a fetch-based HTTP client. Request bodies are
serialized with `JSON.stringify(payload)` and responses are returned as the
plain interface (`await res.json()` cast to the type) — no runtime marshalling.

## Relationship to the `types` **preset**

The `types` *profile* is distinct from the [`types` preset](./types.md): the
preset emits simple type aliases and enums derived from the whole document,
while the profile emits idiomatic **interface models** (payloads, parameters,
headers) for REST consumers. Use the profile when you want ready-to-consume
request/response types; use the preset when you just want shared type aliases.

## `modelType` (opt in without a profile)

Both the [`payloads`](./payloads.md) and [`parameters`](./parameters.md)
generators accept a `modelType: 'class' | 'interface'` option (default
`'class'`, which preserves the AsyncAPI/broker output). Setting
`modelType: 'interface'` is exactly what the profiles do under the hood, so you
can opt individual generators into interface output without adopting a whole
profile:

```js
{
preset: 'payloads',
outputPath: './src/payloads',
modelType: 'interface'
}
```
2 changes: 2 additions & 0 deletions docs/migrations/v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,7 @@ import * as NodeFetch from 'node-fetch';







14 changes: 12 additions & 2 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ $ npm install -g @the-codegen-project/cli
$ codegen COMMAND
running command...
$ codegen (--version)
@the-codegen-project/cli/0.76.0 linux-x64 node-v22.23.1
@the-codegen-project/cli/0.76.0 darwin-arm64 node-v25.9.0
$ codegen --help [COMMAND]
USAGE
$ codegen COMMAND
Expand All @@ -20,7 +20,16 @@ USAGE
## Table of contents

<!-- toc -->
* [CLI Usage](#cli-usage)

- [Commands](#commands)
- [`codegen autocomplete [SHELL]`](#codegen-autocomplete-shell)
- [`codegen base`](#codegen-base)
- [`codegen generate [FILE]`](#codegen-generate-file)
- [`codegen help [COMMAND]`](#codegen-help-command)
- [`codegen init`](#codegen-init)
- [`codegen telemetry ACTION`](#codegen-telemetry-action)
- [`codegen version`](#codegen-version)

<!-- tocstop -->

## Commands
Expand Down Expand Up @@ -235,3 +244,4 @@ FLAG DESCRIPTIONS

_See code: [@oclif/plugin-version](https://github.com/oclif/plugin-version/blob/v2.1.2/src/commands/version.ts)_
<!-- commandsstop -->

26 changes: 26 additions & 0 deletions schemas/configuration-schema-0-with-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
"importExtension": {
"$ref": "#/definitions/AsyncAPICodegenConfiguration/properties/importExtension"
},
"profile": {
"type": "string",
"enum": [
"types",
"client"
],
"markdownDescription": "High-level profile that expands into the granular generators tuned for OpenAPI REST consumers (plain interfaces, no marshal/unmarshal). \"types\" generates interface payloads + parameters + headers (with standalone serializer functions); \"client\" adds the HTTP fetch client on top. Any explicit generators listed alongside a profile are appended, letting you override individual outputs. [Read more about profiles here](https://the-codegen-project.org/docs/generators)"
},
"generators": {
"type": "array",
"items": {
Expand Down Expand Up @@ -255,6 +263,15 @@
"const": "typescript",
"default": "typescript"
},
"modelType": {
"type": "string",
"enum": [
"class",
"interface"
],
"default": "class",
"markdownDescription": "How payload models are rendered. \"class\" (default) emits class-based models with marshal/unmarshal/validate methods (the AsyncAPI/broker shape). \"interface\" emits plain TypeScript interfaces with no methods — the idiomatic shape for OpenAPI REST consumers, used by the OpenAPI interface/client profiles. [Read more about the payloads generator here](https://the-codegen-project.org/docs/generators/payloads)"
},
"enum": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -329,6 +346,15 @@
"type": "string",
"const": "typescript",
"default": "typescript"
},
"modelType": {
"type": "string",
"enum": [
"class",
"interface"
],
"default": "class",
"markdownDescription": "How parameter models are rendered. \"class\" (default) emits a class with serialization methods (the AsyncAPI/broker shape). \"interface\" emits a plain interface plus standalone serializer functions (serialize<Name>QueryParameters / serialize<Name>Url) — the idiomatic shape for OpenAPI REST consumers, used by the OpenAPI interface/client profiles. [Read more about the parameters generator here](https://the-codegen-project.org/docs/generators/parameters)"
}
},
"additionalProperties": false
Expand Down
26 changes: 26 additions & 0 deletions schemas/configuration-schema-0.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
"importExtension": {
"$ref": "#/definitions/AsyncAPICodegenConfiguration/properties/importExtension"
},
"profile": {
"type": "string",
"enum": [
"types",
"client"
],
"description": "High-level profile that expands into the granular generators tuned for OpenAPI REST consumers (plain interfaces, no marshal/unmarshal). \"types\" generates interface payloads + parameters + headers (with standalone serializer functions); \"client\" adds the HTTP fetch client on top. Any explicit generators listed alongside a profile are appended, letting you override individual outputs. Read more about profiles here"
},
"generators": {
"type": "array",
"items": {
Expand Down Expand Up @@ -255,6 +263,15 @@
"const": "typescript",
"default": "typescript"
},
"modelType": {
"type": "string",
"enum": [
"class",
"interface"
],
"default": "class",
"description": "How payload models are rendered. \"class\" (default) emits class-based models with marshal/unmarshal/validate methods (the AsyncAPI/broker shape). \"interface\" emits plain TypeScript interfaces with no methods — the idiomatic shape for OpenAPI REST consumers, used by the OpenAPI interface/client profiles. Read more about the payloads generator here"
},
"enum": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -329,6 +346,15 @@
"type": "string",
"const": "typescript",
"default": "typescript"
},
"modelType": {
"type": "string",
"enum": [
"class",
"interface"
],
"default": "class",
"description": "How parameter models are rendered. \"class\" (default) emits a class with serialization methods (the AsyncAPI/broker shape). \"interface\" emits a plain interface plus standalone serializer functions (serialize<Name>QueryParameters / serialize<Name>Url) — the idiomatic shape for OpenAPI REST consumers, used by the OpenAPI interface/client profiles. Read more about the parameters generator here"
}
},
"additionalProperties": false
Expand Down
65 changes: 59 additions & 6 deletions src/codegen/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,60 @@ export async function loadAndRealizeConfigFile(filePath?: string): Promise<{
/**
* Ensure that each generator has the default options along side custom properties
*/
/**
* Expand a high-level OpenAPI `profile` into the granular generator list, in
* front of any explicitly-listed generators (which are treated as overrides).
* The profile generators use the default generator ids so the channels/client
* dependency injection in {@link ensureProperGenerators} reuses them instead of
* adding class-mode defaults.
*
* - `types` → interface payloads + parameters (with standalone serializers) +
* headers. No channels, no client.
* - `client` → everything in `types` plus the HTTP fetch client.
*
* This is distinct from the `types` *preset* (simple type aliases/enums): the
* profile emits idiomatic interface models for REST consumers.
*/
function expandOpenAPIProfile(config: TheCodegenConfiguration): void {
const profile = (config as {profile?: 'types' | 'client'}).profile;
if (!profile) {
return;
}
const profileGenerators: Generators[] = [
{
preset: 'payloads',
modelType: 'interface',
outputPath: 'src/payloads'
} as unknown as Generators,
{
preset: 'parameters',
modelType: 'interface',
outputPath: 'src/parameters'
} as unknown as Generators,
{preset: 'headers', outputPath: 'src/headers'} as unknown as Generators
];
if (profile === 'client') {
profileGenerators.push(
{
preset: 'channels',
protocols: ['http_client'],
outputPath: 'src/channels'
} as unknown as Generators,
{
preset: 'client',
protocols: ['http'],
outputPath: 'src/client'
} as unknown as Generators
);
}
config.generators = [...profileGenerators, ...(config.generators ?? [])];
}

export function realizeConfiguration(
config: TheCodegenConfiguration
): TheCodegenConfigurationInternal {
config.generators = config.generators ?? [];
expandOpenAPIProfile(config);

const generatorIds: string[] = [];
for (const [index, generator] of config.generators.entries()) {
Expand Down Expand Up @@ -341,14 +391,17 @@ export async function realizeInMemoryGeneratorContext({
configFilePath: '/virtual-config.mjs'
};
if (config.inputType === 'asyncapi') {
context.asyncapiDocument =
await loadAsyncapiFromMemory(specificationDocument);
context.asyncapiDocument = await loadAsyncapiFromMemory(
specificationDocument
);
} else if (config.inputType === 'openapi') {
context.openapiDocument =
await loadOpenapiFromMemory(specificationDocument);
context.openapiDocument = await loadOpenapiFromMemory(
specificationDocument
);
} else if (config.inputType === 'jsonschema') {
context.jsonSchemaDocument =
loadJsonSchemaFromMemory(specificationDocument);
context.jsonSchemaDocument = loadJsonSchemaFromMemory(
specificationDocument
);
}
return context;
}
Loading
Loading