Skip to content

Commit cc2c41b

Browse files
devin-ai-integration[bot]dannysheridanSwimburger
authored
fix(typescript): align websocket path parameter variable names with ConnectArgs interface (#10377)
* fix(typescript): align websocket path parameter variable names with ConnectArgs interface --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]> Co-authored-by: Niels Swimberghe <[email protected]>
1 parent b9339d3 commit cc2c41b

File tree

13 files changed

+184
-130
lines changed

13 files changed

+184
-130
lines changed

generators/typescript/sdk/client-class-generator/src/websocket/GeneratedDefaultWebsocketImplementation.ts

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import { SetRequired } from "@fern-api/core-utils";
22
import {
33
IntermediateRepresentation,
44
NameAndWireValue,
5+
PathParameter,
56
QueryParameter,
67
WebSocketChannel,
78
WebSocketChannelId
89
} from "@fern-fern/ir-sdk/api";
9-
import { getPropertyKey, getTextOfTsNode, PackageId } from "@fern-typescript/commons";
10+
import {
11+
getParameterNameForPropertyPathParameterName,
12+
getPropertyKey,
13+
getTextOfTsNode,
14+
PackageId
15+
} from "@fern-typescript/commons";
1016
import { ChannelSignature, GeneratedWebsocketImplementation, SdkContext } from "@fern-typescript/contexts";
1117
import {
1218
ClassDeclarationStructure,
@@ -156,7 +162,7 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
156162
properties: [
157163
...(this.channel.pathParameters ?? []).map((pathParameter) => {
158164
return {
159-
name: getPropertyKey(pathParameter.name.originalName),
165+
name: getPropertyKey(this.getPropertyNameOfPathParameter(pathParameter).propertyName),
160166
type: getTextOfTsNode(context.type.getReferenceToType(pathParameter.valueType).typeNode),
161167
hasQuestionToken: false
162168
};
@@ -217,17 +223,33 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
217223

218224
private generateConnectMethodStatements(context: SdkContext): ts.Statement[] {
219225
const bindingElements: ts.BindingElement[] = [];
226+
const usedNames = new Set<string>();
227+
const pathParameterLocalNames = new Map<string, string>();
228+
229+
const getNonConflictingName = (name: string) => {
230+
while (usedNames.has(name)) {
231+
name = `${name}_`;
232+
}
233+
usedNames.add(name);
234+
return name;
235+
};
220236

221237
// Add path parameters binding
222238
for (const pathParameter of [
223239
...this.intermediateRepresentation.pathParameters,
224240
...this.channel.pathParameters
225241
]) {
242+
const propertyNames = this.getPropertyNameOfPathParameter(pathParameter);
243+
const localVarName = getNonConflictingName(propertyNames.safeName);
244+
pathParameterLocalNames.set(pathParameter.name.originalName, localVarName);
245+
226246
bindingElements.push(
227247
ts.factory.createBindingElement(
228248
undefined,
229-
undefined,
230-
ts.factory.createIdentifier(pathParameter.name.originalName)
249+
localVarName !== propertyNames.propertyName
250+
? ts.factory.createStringLiteral(propertyNames.propertyName)
251+
: undefined,
252+
ts.factory.createIdentifier(localVarName)
231253
)
232254
);
233255
}
@@ -411,7 +433,7 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
411433
ts.factory.createIdentifier("socket"),
412434
undefined,
413435
undefined,
414-
this.getReferenceToWebsocket(context)
436+
this.getReferenceToWebsocket(context, pathParameterLocalNames)
415437
)
416438
],
417439
ts.NodeFlags.Const
@@ -427,7 +449,7 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
427449
];
428450
}
429451

430-
private getReferenceToWebsocket(context: SdkContext): ts.Expression {
452+
private getReferenceToWebsocket(context: SdkContext, pathParameterLocalNames: Map<string, string>): ts.Expression {
431453
const baseUrl = this.getBaseUrl(this.channel, context);
432454
const url = buildUrl({
433455
endpoint: {
@@ -442,7 +464,13 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
442464
retainOriginalCasing: this.retainOriginalCasing,
443465
omitUndefined: this.omitUndefined,
444466
getReferenceToPathParameterVariableFromRequest: (pathParameter) => {
445-
return ts.factory.createIdentifier(`args.${pathParameter.name.camelCase.safeName}`);
467+
const localVarName = pathParameterLocalNames.get(pathParameter.name.originalName);
468+
if (localVarName == null) {
469+
throw new Error(
470+
`Could not find local variable name for path parameter: ${pathParameter.name.originalName}`
471+
);
472+
}
473+
return ts.factory.createIdentifier(localVarName);
446474
}
447475
});
448476

@@ -596,4 +624,18 @@ export class GeneratedDefaultWebsocketImplementation implements GeneratedWebsock
596624
this.includeSerdeLayer && !this.retainOriginalCasing ? name.name.camelCase.unsafeName : name.wireValue
597625
};
598626
}
627+
628+
public getPropertyNameOfPathParameter(pathParameter: PathParameter): {
629+
safeName: string;
630+
propertyName: string;
631+
} {
632+
return {
633+
safeName: pathParameter.name.camelCase.safeName,
634+
propertyName: getParameterNameForPropertyPathParameterName({
635+
pathParameterName: pathParameter.name,
636+
retainOriginalCasing: this.retainOriginalCasing,
637+
includeSerdeLayer: this.includeSerdeLayer
638+
})
639+
};
640+
}
599641
}

generators/typescript/sdk/versions.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
2+
- version: 3.28.2
3+
changelogEntry:
4+
- summary: |
5+
Fix inconsistent path parameter casing in the WebSocket connect options.
6+
The casing now follows the same rules as other HTTP path parameters:
7+
- `retainOriginalCasing: true`: use the original casing from the OpenAPI spec, regardless of the `noSerdeLayer` setting.
8+
- `noSerdeLayer: true`: use the original casing from the OpenAPI spec.
9+
- `noSerdeLayer: false`: use camelCase for path parameters.
10+
type: fix
11+
createdAt: "2025-11-06"
12+
irVersion: 61
13+
214
- version: 3.28.1
315
changelogEntry:
416
- summary: |

packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-bearer-auth.json

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,7 @@
13121312
"head": "/realtime/",
13131313
"parts": [
13141314
{
1315-
"pathParameter": "id",
1315+
"pathParameter": "session_id",
13161316
"tail": ""
13171317
}
13181318
]
@@ -1343,22 +1343,22 @@
13431343
"pathParameters": [
13441344
{
13451345
"name": {
1346-
"originalName": "id",
1346+
"originalName": "session_id",
13471347
"camelCase": {
1348-
"unsafeName": "id",
1349-
"safeName": "id"
1348+
"unsafeName": "sessionID",
1349+
"safeName": "sessionID"
13501350
},
13511351
"snakeCase": {
1352-
"unsafeName": "id",
1353-
"safeName": "id"
1352+
"unsafeName": "session_id",
1353+
"safeName": "session_id"
13541354
},
13551355
"screamingSnakeCase": {
1356-
"unsafeName": "ID",
1357-
"safeName": "ID"
1356+
"unsafeName": "SESSION_ID",
1357+
"safeName": "SESSION_ID"
13581358
},
13591359
"pascalCase": {
1360-
"unsafeName": "ID",
1361-
"safeName": "ID"
1360+
"unsafeName": "SessionID",
1361+
"safeName": "SessionID"
13621362
}
13631363
},
13641364
"valueType": {
@@ -2066,22 +2066,22 @@
20662066
"pathParameters": [
20672067
{
20682068
"name": {
2069-
"originalName": "id",
2069+
"originalName": "session_id",
20702070
"camelCase": {
2071-
"unsafeName": "id",
2072-
"safeName": "id"
2071+
"unsafeName": "sessionID",
2072+
"safeName": "sessionID"
20732073
},
20742074
"snakeCase": {
2075-
"unsafeName": "id",
2076-
"safeName": "id"
2075+
"unsafeName": "session_id",
2076+
"safeName": "session_id"
20772077
},
20782078
"screamingSnakeCase": {
2079-
"unsafeName": "ID",
2080-
"safeName": "ID"
2079+
"unsafeName": "SESSION_ID",
2080+
"safeName": "SESSION_ID"
20812081
},
20822082
"pascalCase": {
2083-
"unsafeName": "ID",
2084-
"safeName": "ID"
2083+
"unsafeName": "SessionID",
2084+
"safeName": "SessionID"
20852085
}
20862086
},
20872087
"value": {
@@ -3367,22 +3367,22 @@
33673367
"pathParameters": [
33683368
{
33693369
"name": {
3370-
"originalName": "id",
3370+
"originalName": "session_id",
33713371
"camelCase": {
3372-
"unsafeName": "id",
3373-
"safeName": "id"
3372+
"unsafeName": "sessionID",
3373+
"safeName": "sessionID"
33743374
},
33753375
"snakeCase": {
3376-
"unsafeName": "id",
3377-
"safeName": "id"
3376+
"unsafeName": "session_id",
3377+
"safeName": "session_id"
33783378
},
33793379
"screamingSnakeCase": {
3380-
"unsafeName": "ID",
3381-
"safeName": "ID"
3380+
"unsafeName": "SESSION_ID",
3381+
"safeName": "SESSION_ID"
33823382
},
33833383
"pascalCase": {
3384-
"unsafeName": "ID",
3385-
"safeName": "ID"
3384+
"unsafeName": "SessionID",
3385+
"safeName": "SessionID"
33863386
}
33873387
},
33883388
"value": {
@@ -3391,11 +3391,11 @@
33913391
"primitive": {
33923392
"type": "string",
33933393
"string": {
3394-
"original": "id"
3394+
"original": "session_id"
33953395
}
33963396
}
33973397
},
3398-
"jsonExample": "id"
3398+
"jsonExample": "session_id"
33993399
}
34003400
}
34013401
],
@@ -3981,7 +3981,7 @@
39813981
}
39823982
}
39833983
],
3984-
"url": "/realtime/id",
3984+
"url": "/realtime/session_id",
39853985
"docs": null
39863986
}
39873987
],

packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-inferred-auth.json

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,7 +3805,7 @@
38053805
"head": "/realtime/",
38063806
"parts": [
38073807
{
3808-
"pathParameter": "id",
3808+
"pathParameter": "session_id",
38093809
"tail": ""
38103810
}
38113811
]
@@ -3836,22 +3836,22 @@
38363836
"pathParameters": [
38373837
{
38383838
"name": {
3839-
"originalName": "id",
3839+
"originalName": "session_id",
38403840
"camelCase": {
3841-
"unsafeName": "id",
3842-
"safeName": "id"
3841+
"unsafeName": "sessionID",
3842+
"safeName": "sessionID"
38433843
},
38443844
"snakeCase": {
3845-
"unsafeName": "id",
3846-
"safeName": "id"
3845+
"unsafeName": "session_id",
3846+
"safeName": "session_id"
38473847
},
38483848
"screamingSnakeCase": {
3849-
"unsafeName": "ID",
3850-
"safeName": "ID"
3849+
"unsafeName": "SESSION_ID",
3850+
"safeName": "SESSION_ID"
38513851
},
38523852
"pascalCase": {
3853-
"unsafeName": "ID",
3854-
"safeName": "ID"
3853+
"unsafeName": "SessionID",
3854+
"safeName": "SessionID"
38553855
}
38563856
},
38573857
"valueType": {
@@ -4559,22 +4559,22 @@
45594559
"pathParameters": [
45604560
{
45614561
"name": {
4562-
"originalName": "id",
4562+
"originalName": "session_id",
45634563
"camelCase": {
4564-
"unsafeName": "id",
4565-
"safeName": "id"
4564+
"unsafeName": "sessionID",
4565+
"safeName": "sessionID"
45664566
},
45674567
"snakeCase": {
4568-
"unsafeName": "id",
4569-
"safeName": "id"
4568+
"unsafeName": "session_id",
4569+
"safeName": "session_id"
45704570
},
45714571
"screamingSnakeCase": {
4572-
"unsafeName": "ID",
4573-
"safeName": "ID"
4572+
"unsafeName": "SESSION_ID",
4573+
"safeName": "SESSION_ID"
45744574
},
45754575
"pascalCase": {
4576-
"unsafeName": "ID",
4577-
"safeName": "ID"
4576+
"unsafeName": "SessionID",
4577+
"safeName": "SessionID"
45784578
}
45794579
},
45804580
"value": {
@@ -5860,22 +5860,22 @@
58605860
"pathParameters": [
58615861
{
58625862
"name": {
5863-
"originalName": "id",
5863+
"originalName": "session_id",
58645864
"camelCase": {
5865-
"unsafeName": "id",
5866-
"safeName": "id"
5865+
"unsafeName": "sessionID",
5866+
"safeName": "sessionID"
58675867
},
58685868
"snakeCase": {
5869-
"unsafeName": "id",
5870-
"safeName": "id"
5869+
"unsafeName": "session_id",
5870+
"safeName": "session_id"
58715871
},
58725872
"screamingSnakeCase": {
5873-
"unsafeName": "ID",
5874-
"safeName": "ID"
5873+
"unsafeName": "SESSION_ID",
5874+
"safeName": "SESSION_ID"
58755875
},
58765876
"pascalCase": {
5877-
"unsafeName": "ID",
5878-
"safeName": "ID"
5877+
"unsafeName": "SessionID",
5878+
"safeName": "SessionID"
58795879
}
58805880
},
58815881
"value": {
@@ -5884,11 +5884,11 @@
58845884
"primitive": {
58855885
"type": "string",
58865886
"string": {
5887-
"original": "id"
5887+
"original": "session_id"
58885888
}
58895889
}
58905890
},
5891-
"jsonExample": "id"
5891+
"jsonExample": "session_id"
58925892
}
58935893
}
58945894
],
@@ -6474,7 +6474,7 @@
64746474
}
64756475
}
64766476
],
6477-
"url": "/realtime/id",
6477+
"url": "/realtime/session_id",
64786478
"docs": null
64796479
}
64806480
],

0 commit comments

Comments
 (0)