Skip to content

Commit 3ebeaac

Browse files
committed
feat: improve channel protocol structure (#298)
1 parent f65c0ed commit 3ebeaac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+8420
-7063
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ dist
1313
coverage
1414
test/config/src/__gen__/
1515
playground
16-
test/codegen/generators/*/output
16+
test/codegen/generators/*/output
17+
.claude

docs/generators/channels.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,34 @@ Depending on which protocol, these are the dependencies:
5252
- `HTTP`: https://github.com/node-fetch/node-fetch v2
5353
- `WebSocket`: https://github.com/websockets/ws v8
5454

55-
For TypeScript what is generated is a single file that include functions to help easier interact with AsyncAPI channels. For example;
55+
For TypeScript, the generator creates one file per protocol plus an index file that re-exports all protocols as namespaces. For example;
5656

5757
```ts
58-
import { Protocols } from 'src/__gen__/index';
59-
const { nats, kafka, mqtt, amqp, event_source, ... } = Protocols;
60-
const { jetStreamPublishTo..., jetStreamPullSubscribeTo..., jetStreamPushSubscriptionFrom..., publishTo..., subscribeTo... } = nats;
58+
// Import specific functions from a protocol file
59+
import {
60+
jetStreamPublishToSendUserSignedup,
61+
subscribeToReceiveUserSignedup,
62+
publishToSendUserSignedup
63+
} from 'src/__gen__/nats';
64+
65+
// Or import the entire protocol namespace
66+
import * as nats from 'src/__gen__/nats';
67+
68+
// Or import all protocols from the index
69+
import { nats, kafka, mqtt, amqp, event_source } from 'src/__gen__/index';
6170
```
6271

63-
First we import the generated file, which is located based on your `outputPath` in the generator options.
72+
The generated file structure is:
73+
```
74+
outputPath/
75+
├── index.ts # Re-exports all protocol namespaces
76+
├── nats.ts # NATS-specific functions
77+
├── kafka.ts # Kafka-specific functions
78+
├── mqtt.ts # MQTT-specific functions
79+
├── amqp.ts # AMQP-specific functions
80+
├── event_source.ts # EventSource-specific functions
81+
├── http_client.ts # HTTP client-specific functions
82+
└── websocket.ts # WebSocket-specific functions
83+
```
6484

65-
Next we import the desired protocol and then we have access to all the support functions. These support functions are an easy way to interact with channels defined in your AsyncAPI document. Take notice it does not care which operations you have defined.
85+
Each protocol file contains standalone exported functions for interacting with channels defined in your AsyncAPI document.

docs/migrations/v0.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ sidebar_position: 99
99
* [Breaking Changes 0.39.0](#breaking-changes-0390)
1010
+ [Functions Parameters](#functions-parameters)
1111
* [Breaking Changes 0.55.1](#breaking-changes-0551)
12+
* [Breaking Changes 0.61.0](#breaking-changes-0610)
13+
+ [Channels Multi-File Output](#channels-multi-file-output)
1214

1315
<!-- tocstop -->
1416

@@ -63,6 +65,59 @@ const subscriber = await jetStreamPullSubscribeToReceiveUserSignedup({
6365

6466
We upgraded the AsyncAPI Modelina dependency to the `next` version so for the next few versions it will contain breaking changes as we continue to improve the tool.
6567

68+
## Breaking Changes 0.61.0
69+
70+
### Channels Multi-File Output
71+
72+
The `channels` generator now outputs one file per protocol instead of a single file with a `Protocols` object. This change improves tree-shaking, reduces bundle size, and provides better code organization.
73+
74+
**Before (v0.60.x and earlier):**
75+
```typescript
76+
// Single file with Protocols object containing all protocols
77+
import { Protocols } from './channels/index';
78+
const { nats } = Protocols;
79+
const { publishToSendUserSignedup, subscribeToReceiveUserSignedup } = nats;
80+
81+
// Or destructure directly
82+
const { nats: { publishToSendUserSignedup } } = Protocols;
83+
```
84+
85+
**After (v0.61.0+):**
86+
```typescript
87+
// Option 1: Import specific functions directly from protocol file
88+
import {
89+
publishToSendUserSignedup,
90+
subscribeToReceiveUserSignedup
91+
} from './channels/nats';
92+
93+
// Option 2: Import the entire protocol as a namespace
94+
import * as nats from './channels/nats';
95+
nats.publishToSendUserSignedup({ ... });
96+
97+
// Option 3: Import from index (protocols are re-exported as namespaces)
98+
import { nats, kafka, mqtt } from './channels/index';
99+
nats.publishToSendUserSignedup({ ... });
100+
```
101+
102+
**New file structure:**
103+
```
104+
outputPath/
105+
├── index.ts # Re-exports all protocol namespaces
106+
├── nats.ts # NATS-specific functions
107+
├── kafka.ts # Kafka-specific functions
108+
├── mqtt.ts # MQTT-specific functions
109+
├── amqp.ts # AMQP-specific functions
110+
├── event_source.ts # EventSource-specific functions
111+
├── http_client.ts # HTTP client-specific functions
112+
└── websocket.ts # WebSocket-specific functions
113+
```
114+
115+
**Migration steps:**
116+
1. Replace `import { Protocols } from './channels'` with direct imports from protocol files
117+
2. Remove destructuring of the `Protocols` object
118+
3. Update function calls - functions are now standalone exports, not object properties
119+
4. Optionally use namespace imports (`import * as nats from './channels/nats'`) to keep similar syntax
120+
66121

67122

68123

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@
119119
"bump:version": "npm --no-git-tag-version --allow-same-version version $VERSION",
120120
"runtime:prepare": "npm link",
121121
"runtime:typescript": "npm run runtime:typescript:setup && npm run runtime:typescript:test",
122-
"runtime:typescript:setup": "npm run runtime:prepare && npm run runtime:services:start && npm run runtime:typescript:generate",
122+
"runtime:typescript:clean": "rimraf test/runtime/typescript/src",
123+
"runtime:typescript:setup": "npm run runtime:typescript:clean && npm run runtime:prepare && npm run runtime:services:start && npm run runtime:typescript:generate",
123124
"runtime:typescript:generate": "cd test/runtime/typescript && npm ci && npm run generate",
124125
"runtime:typescript:test": "cd test/runtime/typescript && npm run test",
125126
"runtime:services:start": "npm run runtime:nats:start && npm run runtime:kafka:start && npm run runtime:mqtt:start && npm run runtime:amqp:start",
@@ -134,7 +135,7 @@
134135
"runtime:amqp:stop": "cd test/runtime && docker compose -f ./docker-compose-amqp.yml down",
135136
"test:blackbox": "concurrently --group -n typescript \"npm run test:blackbox:typescript\"",
136137
"test:blackbox:typescript": "jest ./test/blackbox/typescript.spec.ts",
137-
"prepare:pr": "npm run build && npm run format && npm run lint:fix && npm run test:update"
138+
"prepare:pr": "npm run build && npm run format && npm run lint:fix && npm run test:update && npm run runtime:typescript:generate"
138139
},
139140
"engines": {
140141
"node": ">=18.0.0"

src/codegen/generators/typescript/channels/asyncapi.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from './types';
1818
import {findNameFromChannel} from '../../../utils';
1919
import {ConstrainedObjectModel, OutputModel} from '@asyncapi/modelina';
20+
import {collectProtocolDependencies} from './utils';
2021
import {generateNatsChannels} from './protocols/nats';
2122
import {generateKafkaChannels} from './protocols/kafka';
2223
import {generateMqttChannels} from './protocols/mqtt';
@@ -82,14 +83,21 @@ export async function generateTypeScriptChannelsForAsyncAPI(
8283
string,
8384
TypeScriptChannelRenderedFunctionType[]
8485
>,
85-
dependencies: string[]
86+
protocolDependencies: Record<string, string[]>
8687
): Promise<void> {
8788
const {asyncapiDocument} = validateAsyncapiContext(context);
8889
const channels = asyncapiDocument!
8990
.allChannels()
9091
.all()
9192
.filter((channel) => channel.address() && channel.messages().length > 0);
9293

94+
// Collect payload/parameter/header imports for each protocol
95+
for (const protocol of protocolsToUse) {
96+
// eslint-disable-next-line security/detect-object-injection
97+
const deps = protocolDependencies[protocol];
98+
collectProtocolDependencies(payloads, parameters, headers, context, deps);
99+
}
100+
93101
for (const channel of channels) {
94102
const subName = findNameFromChannel(channel);
95103
let parameter: OutputModel | undefined = undefined;
@@ -123,7 +131,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
123131
channel,
124132
protocolCodeFunctions,
125133
externalProtocolFunctionInformation,
126-
dependencies
134+
protocolDependencies['nats']
127135
);
128136
break;
129137
case 'kafka':
@@ -132,7 +140,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
132140
channel,
133141
protocolCodeFunctions,
134142
externalProtocolFunctionInformation,
135-
dependencies
143+
protocolDependencies['kafka']
136144
);
137145
break;
138146
case 'mqtt':
@@ -141,7 +149,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
141149
channel,
142150
protocolCodeFunctions,
143151
externalProtocolFunctionInformation,
144-
dependencies
152+
protocolDependencies['mqtt']
145153
);
146154
break;
147155
case 'amqp':
@@ -150,7 +158,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
150158
channel,
151159
protocolCodeFunctions,
152160
externalProtocolFunctionInformation,
153-
dependencies
161+
protocolDependencies['amqp']
154162
);
155163
break;
156164
case 'http_client':
@@ -159,7 +167,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
159167
channel,
160168
protocolCodeFunctions,
161169
externalProtocolFunctionInformation,
162-
dependencies
170+
protocolDependencies['http_client']
163171
);
164172
break;
165173
case 'event_source':
@@ -168,7 +176,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
168176
channel,
169177
protocolCodeFunctions,
170178
externalProtocolFunctionInformation,
171-
dependencies
179+
protocolDependencies['event_source']
172180
);
173181
break;
174182
case 'websocket':
@@ -177,7 +185,7 @@ export async function generateTypeScriptChannelsForAsyncAPI(
177185
channel,
178186
protocolCodeFunctions,
179187
externalProtocolFunctionInformation,
180-
dependencies
188+
protocolDependencies['websocket']
181189
);
182190
break;
183191
default:

0 commit comments

Comments
 (0)