Skip to content

Commit d1d178b

Browse files
authored
feat: add models generator (#259)
1 parent 14fe90e commit d1d178b

File tree

23 files changed

+1624
-425
lines changed

23 files changed

+1624
-425
lines changed

.cursorignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
node_modules
2-
./coverage

docs/generators/README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ All available generators, across languages and inputs:
1515
- [`types`](./types.md)
1616
- [`channels`](./channels.md)
1717
- [`client`](./client.md)
18+
- [`models`](./models.md)
1819
- [`custom`](./custom.md)
1920

20-
| **Inputs** | [`payloads`](./payloads.md) | [`parameters`](./parameters.md) | [`headers`](./headers.md) | [`types`](./types.md) | [`channels`](./channels.md) | [`client`](./client.md) | [`custom`](./custom.md) |
21-
|---|---|---|---|---|---|---|---|
22-
| AsyncAPI | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
23-
| OpenAPI | ✔️ | ✔️ | ✔️ | ✔️ ||| ✔️ |
21+
| **Inputs** | [`payloads`](./payloads.md) | [`parameters`](./parameters.md) | [`headers`](./headers.md) | [`types`](./types.md) | [`channels`](./channels.md) | [`client`](./client.md) | [`models`](./models.md) | [`custom`](./custom.md) |
22+
|---|---|---|---|---|---|---|---|---|
23+
| AsyncAPI | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
24+
| OpenAPI | ✔️ | ✔️ | ✔️ | ✔️ ||| ✔️ | ✔️ |
2425

25-
| **Languages** | [`payloads`](./payloads.md) | [`parameters`](./parameters.md) | [`headers`](./headers.md) | [`types`](./types.md) | [`channels`](./channels.md) | [`client`](./client.md) | [`custom`](./custom.md) |
26-
|---|---|---|---|---|---|---|---|
27-
| TypeScript | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
26+
| **Languages** | [`payloads`](./payloads.md) | [`parameters`](./parameters.md) | [`headers`](./headers.md) | [`types`](./types.md) | [`channels`](./channels.md) | [`client`](./client.md) | [`models`](./models.md) | [`custom`](./custom.md) |
27+
|---|---|---|---|---|---|---|---|---|
28+
| TypeScript | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |

docs/generators/models.md

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
---
2+
sidebar_position: 99
3+
---
4+
5+
# 🏗️ Models
6+
7+
```js
8+
export default {
9+
...,
10+
generators: [
11+
{
12+
preset: 'models',
13+
outputPath: './src/models',
14+
language: 'typescript',
15+
renderers: [...],
16+
options: {...}
17+
}
18+
]
19+
};
20+
```
21+
22+
The `models` preset provides native integration with [AsyncAPI Modelina](https://modelina.org) for generating TypeScript models directly from AsyncAPI and OpenAPI documents. This generator exposes Modelina's full capabilities, giving you complete control over model generation.
23+
24+
This is supported through the following inputs: `asyncapi`, `openapi`
25+
26+
It supports the following languages; [`typescript`](#typescript)
27+
28+
## Core Features
29+
30+
- **Native Modelina Integration**: Direct access to Modelina's TypeScript generator
31+
- **Custom Presets**: Full control over generated code through Modelina's preset system
32+
- **Flexible Options**: Configure all TypeScript generation options
33+
- **Production Ready**: Generate models that are immediately usable in your applications
34+
35+
## Configuration
36+
37+
### `renderers`
38+
39+
The `renderers` property exposes Modelina's [preset system](https://raw.githubusercontent.com/asyncapi/modelina/refs/heads/master/docs/presets.md), allowing you to customize every aspect of the generated models.
40+
41+
Presets can:
42+
- Add custom content to classes, interfaces, enums, and types
43+
- Override default rendering behavior
44+
- Inject validation logic, serialization methods, or custom properties
45+
- Apply consistent formatting and documentation
46+
47+
### `options`
48+
49+
The `options` property provides access to all [Modelina TypeScript options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md), including:
50+
51+
- Model types (class, interface, type alias)
52+
- Enum generation styles
53+
- Property naming conventions
54+
- Module system preferences
55+
- Type mappings and constraints
56+
57+
## Examples
58+
59+
### Basic Usage
60+
61+
```js
62+
export default {
63+
inputType: 'asyncapi',
64+
inputPath: 'asyncapi.json',
65+
language: 'typescript',
66+
generators: [
67+
{
68+
preset: 'models',
69+
outputPath: './src/models'
70+
}
71+
]
72+
};
73+
```
74+
75+
### Using Built-in Presets
76+
77+
```js
78+
import { modelina } from '@the-codegen-project/cli';
79+
const { TS_COMMON_PRESET } = modelina;
80+
81+
export default {
82+
inputType: 'asyncapi',
83+
inputPath: 'asyncapi.json',
84+
language: 'typescript',
85+
generators: [
86+
{
87+
preset: 'models',
88+
renderers: [
89+
{
90+
preset: TS_COMMON_PRESET,
91+
options: {
92+
marshalling: true
93+
}
94+
}
95+
],
96+
outputPath: './src/models'
97+
}
98+
]
99+
};
100+
```
101+
102+
### Custom Presets
103+
104+
```js
105+
export default {
106+
inputType: 'asyncapi',
107+
inputPath: 'asyncapi.json',
108+
language: 'typescript',
109+
generators: [
110+
{
111+
preset: 'models',
112+
renderers: [
113+
{
114+
class: {
115+
self: ({model}) => `class ${model.name} {}`
116+
},
117+
interface: {
118+
self: ({model}) => `interface ${model.name} {}`
119+
},
120+
type: {
121+
self: ({model}) => `type ${model.name} = string;`
122+
}
123+
}
124+
],
125+
outputPath: './src/models'
126+
}
127+
]
128+
};
129+
```
130+
131+
### Advanced Configuration with Options
132+
133+
```js
134+
export default {
135+
inputType: 'asyncapi',
136+
inputPath: 'asyncapi.json',
137+
language: 'typescript',
138+
generators: [
139+
{
140+
preset: 'models',
141+
options: {
142+
modelType: 'interface',
143+
enumType: 'union',
144+
mapType: 'indexedObject',
145+
moduleSystem: 'ESM',
146+
rawPropertyNames: false,
147+
useJavascriptReservedKeywords: false
148+
},
149+
renderers: [
150+
{
151+
interface: {
152+
property: ({ content, property }) => {
153+
return `/** ${property.property.description || 'Auto-generated property'} */\n${content}`;
154+
}
155+
}
156+
}
157+
],
158+
outputPath: './src/models'
159+
}
160+
]
161+
};
162+
```
163+
164+
## Languages
165+
166+
### TypeScript
167+
168+
The TypeScript implementation provides full access to Modelina's TypeScript generator capabilities.
169+
170+
**Dependencies**: None (generates plain TypeScript)
171+
172+
**Supported Features**:
173+
- Classes, interfaces, type aliases, and enums
174+
- Complex nested types and circular references
175+
- Union types and discriminated unions
176+
- Optional and required properties
177+
- Custom property naming and constraints
178+
- Marshalling and unmarshalling methods (with TS_COMMON_PRESET)
179+
- JSON Schema validation (with custom presets)
180+
181+
**Common Options**:
182+
183+
| Option | Type | Default | Description |
184+
|--------|------|---------|-------------|
185+
| `modelType` | `'class' \| 'interface'` | `'class'` | Type of models to generate |
186+
| `enumType` | `'enum' \| 'union'` | `'enum'` | How to render enum types |
187+
| `mapType` | `'indexedObject' \| 'record'` | `'record'` | How to render map/dictionary types |
188+
| `moduleSystem` | `'CJS' \| 'ESM'` | `'ESM'` | Module system to use |
189+
| `rawPropertyNames` | `boolean` | `false` | Use raw property names without transformation |
190+
| `useJavascriptReservedKeywords` | `boolean` | `true` | Allow JavaScript reserved keywords |
191+
192+
**Common Presets**:
193+
194+
| Preset | Description |
195+
|--------|-------------|
196+
| `TS_COMMON_PRESET` | Adds marshalling/unmarshalling methods |
197+
| `TS_DESCRIPTION_PRESET` | Adds JSDoc descriptions from schemas |
198+
| Custom presets | Define your own rendering behavior |
199+
200+
**Generated Code Structure**:
201+
202+
```typescript
203+
// Example generated class with TS_COMMON_PRESET
204+
export class UserProfile {
205+
private _id?: string;
206+
private _email?: string;
207+
private _name?: string;
208+
209+
constructor(input: {
210+
id?: string;
211+
email?: string;
212+
name?: string;
213+
}) {
214+
this._id = input.id;
215+
this._email = input.email;
216+
this._name = input.name;
217+
}
218+
219+
get id(): string | undefined { return this._id; }
220+
set id(id: string | undefined) { this._id = id; }
221+
222+
get email(): string | undefined { return this._email; }
223+
set email(email: string | undefined) { this._email = email; }
224+
225+
get name(): string | undefined { return this._name; }
226+
set name(name: string | undefined) { this._name = name; }
227+
228+
public marshal(): string {
229+
return JSON.stringify({
230+
id: this.id,
231+
email: this.email,
232+
name: this.name
233+
});
234+
}
235+
236+
public static unmarshal(data: string): UserProfile {
237+
const obj = JSON.parse(data);
238+
return new UserProfile(obj);
239+
}
240+
}
241+
```
242+
243+
## Integration Examples
244+
245+
### With Channels Generator
246+
247+
```js
248+
export default {
249+
inputType: 'asyncapi',
250+
inputPath: 'asyncapi.json',
251+
language: 'typescript',
252+
generators: [
253+
{
254+
preset: 'models',
255+
renderers: [
256+
{
257+
preset: TS_COMMON_PRESET,
258+
options: { marshalling: true }
259+
}
260+
],
261+
outputPath: './src/models'
262+
},
263+
{
264+
preset: 'channels',
265+
outputPath: './src/channels',
266+
protocols: ['nats', 'kafka']
267+
}
268+
]
269+
};
270+
```
271+
272+
### With Custom Validation
273+
274+
```js
275+
export default {
276+
inputType: 'asyncapi',
277+
inputPath: 'asyncapi.json',
278+
language: 'typescript',
279+
generators: [
280+
{
281+
preset: 'models',
282+
renderers: [
283+
{
284+
class: {
285+
additionalContent: ({ content, model }) => {
286+
return `${content}
287+
288+
public validate(): boolean {
289+
// Custom validation logic
290+
return true;
291+
}`;
292+
}
293+
}
294+
}
295+
],
296+
outputPath: './src/models'
297+
}
298+
]
299+
};
300+
```
301+
302+
## Resources
303+
304+
- [Modelina Presets Documentation](https://github.com/asyncapi/modelina/blob/master/refs/heads/master/docs/presets.md)
305+
- [Modelina TypeScript Options](https://github.com/asyncapi/modelina/blob/master/docs/languages/TypeScript.md)
306+
- [Modelina Examples](https://github.com/asyncapi/modelina/tree/master/examples)

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"bugs": "https://github.com/the-codegen-project/cli/issues",
99
"dependencies": {
1010
"@asyncapi/avro-schema-parser": "^3.0.24",
11-
"@asyncapi/modelina": "^5.3.5",
11+
"@asyncapi/modelina": "^5.7.2",
1212
"@asyncapi/openapi-schema-parser": "^3.0.24",
1313
"@asyncapi/parser": "^3.4.0",
1414
"@asyncapi/protobuf-schema-parser": "^3.5.1",

0 commit comments

Comments
 (0)