Skip to content

Commit 0a26e17

Browse files
Himenonclaude
andcommitted
fix: path parameters always win over same-named query parameters in generated TypeScript interfaces
When a PathItem defines both a path parameter and a query parameter with the same name (e.g. Kubernetes /api/v1/nodes/{name}/proxy/{path}), the previous implementation used the parameter name alone as the deduplication key in generatePropertySignatures. This caused the optional query parameter to overwrite the required path parameter, producing `path?: string` instead of the correct `path: string`. Fix: sort parameters before reducing so that path parameters are processed last. Since they win in the final reduce assignment, their required status is always preserved in the generated TypeScript interface. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2b786e7 commit 0a26e17

10 files changed

Lines changed: 4229 additions & 4220 deletions

File tree

src/internal/OpenApiTools/components/Parameter.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,16 @@ export const generatePropertySignatures = (
109109
context: ToTypeNode.Context,
110110
converterContext: ConverterContext.Types,
111111
): string[] => {
112-
const typeElementMap = parameters.reduce<Record<string, string>>((all, parameter) => {
112+
// Path parameters must be processed last so they win over same-named query/header
113+
// parameters when building the TypeScript interface (path params are always required).
114+
const sorted = [...parameters].sort((a, b): number => {
115+
const aIsPath = !Guard.isReference(a) && a.in === "path";
116+
const bIsPath = !Guard.isReference(b) && b.in === "path";
117+
if (aIsPath && !bIsPath) return 1;
118+
if (!aIsPath && bIsPath) return -1;
119+
return 0;
120+
});
121+
const typeElementMap = sorted.reduce<Record<string, string>>((all, parameter) => {
113122
const { name, typeElement } = generatePropertySignatureObject(
114123
entryPoint,
115124
currentPoint,

test/__tests__/class/__snapshots__/cloudflare-test.ts.snap

Lines changed: 181 additions & 181 deletions
Large diffs are not rendered by default.

test/__tests__/class/__snapshots__/kubernetes-test.ts.snap

Lines changed: 1832 additions & 1832 deletions
Large diffs are not rendered by default.

test/__tests__/class/__snapshots__/spit-code-test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ export interface Response$getReferenceItems$Status$200 {
4848
};
4949
}
5050
export interface Parameter$searchBook {
51-
"book.name": string;
5251
"from.publishedAt"?: number;
52+
"book.name": string;
5353
}
5454
export interface Response$searchBook$Status$200 {
5555
"application/json": {

test/__tests__/class/__snapshots__/typedef-with-template-test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ export interface Response$getReferenceItems$Status$200 {
334334
};
335335
}
336336
export interface Parameter$searchBook {
337-
"book.name": string;
338337
"from.publishedAt"?: number;
338+
"book.name": string;
339339
}
340340
export interface Response$searchBook$Status$200 {
341341
"application/json": {
@@ -1004,8 +1004,8 @@ export interface Response$getReferenceItems$Status$200 {
10041004
};
10051005
}
10061006
export interface Parameter$searchBook {
1007-
"book.name": string;
10081007
"from.publishedAt"?: number;
1008+
"book.name": string;
10091009
}
10101010
export interface Response$searchBook$Status$200 {
10111011
"application/json": {
@@ -1757,20 +1757,20 @@ export interface Response$getItemById$Status$200 {
17571757
};
17581758
}
17591759
export interface Parameter$getNodeProxyWithPath {
1760+
path: string;
17601761
name: string;
1761-
path?: string;
17621762
}
17631763
export interface Response$getNodeProxyWithPath$Status$200 {
17641764
"application/json": string;
17651765
}
17661766
export interface Parameter$headNodeProxyWithPath {
1767+
path: string;
17671768
name: string;
1768-
path?: string;
17691769
}
17701770
export interface Parameter$getUserPost {
1771+
include?: string;
17711772
userId: string;
17721773
postId: number;
1773-
include?: string;
17741774
}
17751775
export interface Response$getUserPost$Status$200 {
17761776
"application/json": {

test/__tests__/currying-functional/__snapshots__/coudflare-test.ts.snap

Lines changed: 181 additions & 181 deletions
Large diffs are not rendered by default.

test/__tests__/functional/__snapshots__/coudflare-test.ts.snap

Lines changed: 181 additions & 181 deletions
Large diffs are not rendered by default.

test/__tests__/functional/__snapshots__/kubernetes-test.ts.snap

Lines changed: 1832 additions & 1832 deletions
Large diffs are not rendered by default.

test/__tests__/functional/__snapshots__/spit-code-test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ export interface Response$getReferenceItems$Status$200 {
4848
};
4949
}
5050
export interface Parameter$searchBook {
51-
"book.name": string;
5251
"from.publishedAt"?: number;
52+
"book.name": string;
5353
}
5454
export interface Response$searchBook$Status$200 {
5555
"application/json": {

test/__tests__/functional/__snapshots__/typedef-with-template-test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ export interface Response$getReferenceItems$Status$200 {
334334
};
335335
}
336336
export interface Parameter$searchBook {
337-
"book.name": string;
338337
"from.publishedAt"?: number;
338+
"book.name": string;
339339
}
340340
export interface Response$searchBook$Status$200 {
341341
"application/json": {
@@ -1010,8 +1010,8 @@ export interface Response$getReferenceItems$Status$200 {
10101010
};
10111011
}
10121012
export interface Parameter$searchBook {
1013-
"book.name": string;
10141013
"from.publishedAt"?: number;
1014+
"book.name": string;
10151015
}
10161016
export interface Response$searchBook$Status$200 {
10171017
"application/json": {
@@ -1774,20 +1774,20 @@ export interface Response$getItemById$Status$200 {
17741774
};
17751775
}
17761776
export interface Parameter$getNodeProxyWithPath {
1777+
path: string;
17771778
name: string;
1778-
path?: string;
17791779
}
17801780
export interface Response$getNodeProxyWithPath$Status$200 {
17811781
"application/json": string;
17821782
}
17831783
export interface Parameter$headNodeProxyWithPath {
1784+
path: string;
17841785
name: string;
1785-
path?: string;
17861786
}
17871787
export interface Parameter$getUserPost {
1788+
include?: string;
17881789
userId: string;
17891790
postId: number;
1790-
include?: string;
17911791
}
17921792
export interface Response$getUserPost$Status$200 {
17931793
"application/json": {

0 commit comments

Comments
 (0)