Skip to content

Commit a1586c0

Browse files
authored
feat: generate JSDoc comments from schema descriptions (including @deprecated) (#348)
1 parent 7a22f99 commit a1586c0

118 files changed

Lines changed: 2487 additions & 335 deletions

File tree

Some content is hidden

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

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ function processOperation(
217217
return undefined;
218218
}
219219

220+
// Extract operation metadata for JSDoc
221+
const description = operation.description ?? operation.summary;
222+
const deprecated = operation.deprecated === true;
223+
220224
// Generate the HTTP client function
221225
return renderHttpFetchClient({
222226
subName: pascalCase(operationId),
@@ -236,7 +240,9 @@ function processOperation(
236240
channelParameters: parameterModel?.model as
237241
| ConstrainedObjectModel
238242
| undefined,
239-
includesStatusCodes: replyIncludesStatusCodes
243+
includesStatusCodes: replyIncludesStatusCodes,
244+
description,
245+
deprecated
240246
});
241247
}
242248

src/codegen/generators/typescript/channels/protocols/amqp/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import {
66
ChannelFunctionTypes,
77
TypeScriptChannelsGeneratorContext
88
} from '../../types';
9-
import {findNameFromOperation, findOperationId} from '../../../../../utils';
9+
import {
10+
findNameFromOperation,
11+
findOperationId,
12+
getOperationMetadata
13+
} from '../../../../../utils';
1014
import {getMessageTypeAndModule} from '../../utils';
1115
import {
1216
shouldRenderFunctionType,
@@ -113,11 +117,15 @@ async function generateForOperations(
113117
`Could not find message type for channel typescript generator for AMQP`
114118
);
115119
}
120+
// Extract operation metadata for JSDoc
121+
const {description, deprecated} = getOperationMetadata(operation);
116122
const updatedContext = {
117123
...amqpContext,
118124
messageType,
119125
messageModule,
120-
subName: findNameFromOperation(operation, channel)
126+
subName: findNameFromOperation(operation, channel),
127+
description,
128+
deprecated
121129
};
122130

123131
renders.push(

src/codegen/generators/typescript/channels/protocols/amqp/publishExchange.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {ChannelFunctionTypes} from '../..';
33
import {SingleFunctionRenderType} from '../../../../../types';
44
import {pascalCase} from '../../../utils';
55
import {RenderRegularParameters} from '../../types';
6+
import {renderChannelJSDoc} from '../../utils';
67

78
export function renderPublishExchange({
89
topic,
@@ -12,7 +13,9 @@ export function renderPublishExchange({
1213
channelHeaders,
1314
subName = pascalCase(topic),
1415
functionName = `publishTo${subName}Exchange`,
15-
additionalProperties
16+
additionalProperties,
17+
description,
18+
deprecated
1619
}: RenderRegularParameters<{
1720
exchange: string | undefined;
1821
}>): SingleFunctionRenderType {
@@ -83,11 +86,16 @@ channel.publish(exchange, routingKey, Buffer.from(dataToSend), publishOptions);`
8386
}
8487
];
8588

86-
const code = `/**
87-
* AMQP publish operation for exchange \`${topic}\`
88-
*
89-
${functionParameters.map((param) => param.jsDoc).join('\n')}
90-
*/
89+
const jsDoc = renderChannelJSDoc({
90+
description,
91+
deprecated,
92+
fallbackDescription: `AMQP publish operation for exchange \`${topic}\``,
93+
parameters: functionParameters.map((param) => ({
94+
jsDoc: param.jsDoc
95+
}))
96+
});
97+
98+
const code = `${jsDoc}
9199
function ${functionName}({
92100
${functionParameters.map((param) => param.parameter).join(', \n ')}
93101
}: {

src/codegen/generators/typescript/channels/protocols/amqp/publishQueue.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {ChannelFunctionTypes} from '../..';
33
import {SingleFunctionRenderType} from '../../../../../types';
44
import {pascalCase} from '../../../utils';
55
import {RenderRegularParameters} from '../../types';
6+
import {renderChannelJSDoc} from '../../utils';
67

78
export function renderPublishQueue({
89
topic,
@@ -11,7 +12,9 @@ export function renderPublishQueue({
1112
channelParameters,
1213
channelHeaders,
1314
subName = pascalCase(topic),
14-
functionName = `publishTo${subName}Queue`
15+
functionName = `publishTo${subName}Queue`,
16+
description,
17+
deprecated
1518
}: RenderRegularParameters): SingleFunctionRenderType {
1619
const addressToUse = channelParameters
1720
? `parameters.getChannelWithParameters('${topic}')`
@@ -80,11 +83,16 @@ channel.sendToQueue(queue, Buffer.from(dataToSend), publishOptions);`;
8083
}
8184
];
8285

83-
const code = `/**
84-
* AMQP publish operation for queue \`${topic}\`
85-
*
86-
${functionParameters.map((param) => param.jsDoc).join('\n')}
87-
*/
86+
const jsDoc = renderChannelJSDoc({
87+
description,
88+
deprecated,
89+
fallbackDescription: `AMQP publish operation for queue \`${topic}\``,
90+
parameters: functionParameters.map((param) => ({
91+
jsDoc: param.jsDoc
92+
}))
93+
});
94+
95+
const code = `${jsDoc}
8896
function ${functionName}({
8997
${functionParameters.map((param) => param.parameter).join(', \n ')}
9098
}: {

src/codegen/generators/typescript/channels/protocols/amqp/subscribeQueue.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {ChannelFunctionTypes} from '../..';
22
import {SingleFunctionRenderType} from '../../../../../types';
33
import {pascalCase} from '../../../utils';
44
import {RenderRegularParameters} from '../../types';
5-
import {getValidationFunctions} from '../../utils';
5+
import {getValidationFunctions, renderChannelJSDoc} from '../../utils';
66

77
export function renderSubscribeQueue({
88
topic,
@@ -12,7 +12,9 @@ export function renderSubscribeQueue({
1212
channelHeaders,
1313
subName = pascalCase(topic),
1414
functionName = `subscribeTo${subName}Queue`,
15-
payloadGenerator
15+
payloadGenerator,
16+
description,
17+
deprecated
1618
}: RenderRegularParameters): SingleFunctionRenderType {
1719
const includeValidation = payloadGenerator.generator.includeValidation;
1820
const addressToUse = channelParameters
@@ -116,11 +118,16 @@ channel.consume(queue, (msg) => {
116118
}
117119
];
118120

119-
const code = `/**
120-
* AMQP subscribe operation for queue \`${topic}\`
121-
*
122-
${functionParameters.map((param) => param.jsDoc).join('\n')}
123-
*/
121+
const jsDoc = renderChannelJSDoc({
122+
description,
123+
deprecated,
124+
fallbackDescription: `AMQP subscribe operation for queue \`${topic}\``,
125+
parameters: functionParameters.map((param) => ({
126+
jsDoc: param.jsDoc
127+
}))
128+
});
129+
130+
const code = `${jsDoc}
124131
function ${functionName}({
125132
${functionParameters.map((param) => param.parameter).join(', \n ')}
126133
}: {

src/codegen/generators/typescript/channels/protocols/eventsource/express.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {ChannelFunctionTypes} from '../..';
33
import {SingleFunctionRenderType} from '../../../../../types';
44
import {findRegexFromChannel, pascalCase} from '../../../utils';
55
import {RenderRegularParameters} from '../../types';
6+
import {renderChannelJSDoc} from '../../utils';
67

78
export function renderExpress({
89
topic,
@@ -11,7 +12,9 @@ export function renderExpress({
1112
channelParameters,
1213
channelHeaders,
1314
subName = pascalCase(topic),
14-
functionName = `register${subName}`
15+
functionName = `register${subName}`,
16+
description,
17+
deprecated
1518
}: RenderRegularParameters): SingleFunctionRenderType {
1619
let addressToUse = topic.replace(/{([^}]+)}/g, ':$1');
1720
addressToUse = addressToUse.startsWith('/')
@@ -64,7 +67,17 @@ export function renderExpress({
6467
}
6568
];
6669

67-
const code = `function ${functionName}({
70+
const jsDoc = renderChannelJSDoc({
71+
description,
72+
deprecated,
73+
fallbackDescription: `Register EventSource endpoint for \`${topic}\``,
74+
parameters: functionParameters.map((param) => ({
75+
jsDoc: param.jsDoc
76+
}))
77+
});
78+
79+
const code = `${jsDoc}
80+
function ${functionName}({
6881
${functionParameters.map((param) => param.parameter).join(', \n ')}
6982
}: {
7083
${functionParameters.map((param) => param.parameterType).join(', \n ')}

src/codegen/generators/typescript/channels/protocols/eventsource/fetch.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
defaultTypeScriptChannelsGenerator,
77
RenderRegularParameters
88
} from '../../types';
9-
import {getValidationFunctions} from '../../utils';
9+
import {getValidationFunctions, renderChannelJSDoc} from '../../utils';
1010

1111
export function renderFetch({
1212
topic,
@@ -19,7 +19,9 @@ export function renderFetch({
1919
additionalProperties = {
2020
fetchDependency: defaultTypeScriptChannelsGenerator.eventSourceDependency
2121
},
22-
payloadGenerator
22+
payloadGenerator,
23+
description,
24+
deprecated
2325
}: RenderRegularParameters<{
2426
fetchDependency: string;
2527
}>): SingleFunctionRenderType {
@@ -75,12 +77,21 @@ export function renderFetch({
7577
}
7678
];
7779

78-
const code = `/**
79-
* Event source fetch for \`${topic}\`
80-
*
81-
${functionParameters.map((param) => param.jsDoc).join('\n')}
82-
* @returns A cleanup function to abort the connection
83-
*/
80+
const jsDoc = renderChannelJSDoc({
81+
description,
82+
deprecated,
83+
fallbackDescription: `Event source fetch for \`${topic}\``,
84+
parameters: [
85+
...functionParameters.map((param) => ({
86+
jsDoc: param.jsDoc
87+
})),
88+
{
89+
jsDoc: ' * @returns A cleanup function to abort the connection'
90+
}
91+
]
92+
});
93+
94+
const code = `${jsDoc}
8495
function ${functionName}({
8596
${functionParameters.map((param) => param.parameter).join(', \n ')}
8697
}: {

src/codegen/generators/typescript/channels/protocols/eventsource/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import {
66
ChannelFunctionTypes,
77
TypeScriptChannelsGeneratorContext
88
} from '../../types';
9-
import {findNameFromOperation, findOperationId} from '../../../../../utils';
9+
import {
10+
findNameFromOperation,
11+
findOperationId,
12+
getOperationMetadata
13+
} from '../../../../../utils';
1014
import {getMessageTypeAndModule} from '../../utils';
1115
import {
1216
shouldRenderFunctionType,
@@ -112,11 +116,15 @@ async function generateForOperations(
112116
`Could not find message type for channel typescript generator for EventSource`
113117
);
114118
}
119+
// Extract operation metadata for JSDoc
120+
const {description, deprecated} = getOperationMetadata(operation);
115121
const updatedContext = {
116122
...eventSourceContext,
117123
messageType,
118124
messageModule,
119-
subName: findNameFromOperation(operation, channel)
125+
subName: findNameFromOperation(operation, channel),
126+
description,
127+
deprecated
120128
};
121129

122130
renders.push(

src/codegen/generators/typescript/channels/protocols/http/client.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import {HttpRenderType} from '../../../../../types';
66
import {pascalCase} from '../../../utils';
77
import {ChannelFunctionTypes, RenderHttpParameters} from '../../types';
8+
import {renderChannelJSDoc} from '../../utils';
89

910
/**
1011
* Renders an HTTP fetch client function for a specific API operation.
@@ -20,7 +21,9 @@ export function renderHttpFetchClient({
2021
servers = [],
2122
subName = pascalCase(requestTopic),
2223
functionName = `${method.toLowerCase()}${subName}`,
23-
includesStatusCodes = false
24+
includesStatusCodes = false,
25+
description,
26+
deprecated
2427
}: RenderHttpParameters): HttpRenderType {
2528
const messageType = requestMessageModule
2629
? `${requestMessageModule}.${requestMessageType}`
@@ -43,6 +46,13 @@ export function renderHttpFetchClient({
4346
method
4447
);
4548

49+
// Generate JSDoc for the function
50+
const jsDoc = renderChannelJSDoc({
51+
description,
52+
deprecated,
53+
fallbackDescription: `HTTP ${method} request to ${requestTopic}`
54+
});
55+
4656
// Generate the function implementation
4757
const functionCode = generateFunctionImplementation({
4858
functionName,
@@ -55,7 +65,8 @@ export function renderHttpFetchClient({
5565
hasParameters,
5666
method,
5767
servers,
58-
includesStatusCodes
68+
includesStatusCodes,
69+
jsDoc
5970
});
6071

6172
const code = `${contextInterface}
@@ -122,6 +133,7 @@ function generateFunctionImplementation(params: {
122133
method: string;
123134
servers: string[];
124135
includesStatusCodes: boolean;
136+
jsDoc: string;
125137
}): string {
126138
const {
127139
functionName,
@@ -134,7 +146,8 @@ function generateFunctionImplementation(params: {
134146
hasParameters,
135147
method,
136148
servers,
137-
includesStatusCodes
149+
includesStatusCodes,
150+
jsDoc
138151
} = params;
139152

140153
const defaultServer = servers[0] ?? "'localhost:3000'";
@@ -170,7 +183,8 @@ function generateFunctionImplementation(params: {
170183
// Generate default context for optional context parameter
171184
const contextDefault = !hasBody && !hasParameters ? ' = {}' : '';
172185

173-
return `async function ${functionName}(context: ${contextInterfaceName}${contextDefault}): Promise<HttpClientResponse<${replyType}>> {
186+
return `${jsDoc}
187+
async function ${functionName}(context: ${contextInterfaceName}${contextDefault}): Promise<HttpClientResponse<${replyType}>> {
174188
// Apply defaults
175189
const config = {
176190
path: '${requestTopic}',

src/codegen/generators/typescript/channels/protocols/http/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
import {
88
findNameFromOperation,
99
findOperationId,
10-
findReplyId
10+
findReplyId,
11+
getOperationMetadata
1112
} from '../../../../../utils';
1213
import {getMessageTypeAndModule} from '../../utils';
1314
import {
@@ -149,6 +150,7 @@ function generateForOperations(
149150
`Could not find reply message type for channel typescript generator for HTTP`
150151
);
151152
}
153+
const {description, deprecated} = getOperationMetadata(operation);
152154
renders.push(
153155
renderHttpFetchClient({
154156
subName: findNameFromOperation(operation, channel),
@@ -160,7 +162,9 @@ function generateForOperations(
160162
method: httpMethod.toUpperCase(),
161163
channelParameters:
162164
parameters !== undefined ? parameters : undefined,
163-
includesStatusCodes: replyIncludesStatusCodes
165+
includesStatusCodes: replyIncludesStatusCodes,
166+
description,
167+
deprecated
164168
})
165169
);
166170
}

0 commit comments

Comments
 (0)