Skip to content

Commit 9fa1ce9

Browse files
authored
fix: path params must not contain any unescaped generic syntax characters (#132)
1 parent 62e852a commit 9fa1ce9

15 files changed

+5145
-5121
lines changed

src/code-templates/_shared/MethodBody/PathParameter.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,21 @@ export const generateUrlTemplateExpression = (
6161
pathParameters: CodeGenerator.PickedParameter[],
6262
): Utils.Params$TemplateExpression => {
6363
const patternMap = pathParameters.reduce<{ [key: string]: string }>((previous, item) => {
64-
return { ...previous, [`{${item.name}}`]: item.name };
64+
previous[`{${item.name}}`] = item.name;
65+
return previous;
6566
}, {});
6667
const urlTemplate: Utils.Params$TemplateExpression = [];
6768
let temporaryStringList: string[] = [];
6869
// TODO generateVariableIdentifierに噛み合わ下げいいように変換する
6970
const replaceText = (text: string): string | undefined => {
7071
let replacedText = text;
71-
Object.keys(patternMap).forEach(pathParameterName => {
72+
for (const pathParameterName of Object.keys(patternMap)) {
7273
if (new RegExp(pathParameterName).test(replacedText)) {
7374
const { text, escaped } = escapeText(patternMap[pathParameterName]);
7475
const variableDeclareText = escaped ? `params.parameter[${text}]` : `params.parameter.${text}`;
7576
replacedText = replacedText.replace(new RegExp(pathParameterName, "g"), variableDeclareText);
7677
}
77-
});
78+
}
7879
return replacedText === text ? undefined : replacedText;
7980
};
8081

@@ -94,9 +95,18 @@ export const generateUrlTemplateExpression = (
9495
});
9596
temporaryStringList = [];
9697
}
98+
99+
/**
100+
* @see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-templating
101+
*/
97102
urlTemplate.push({
98103
type: "property",
99-
value: Utils.generateVariableIdentifier(factory, replacedText),
104+
value: factory.CallExpression.create({
105+
expression: factory.Identifier.create({
106+
name: "encodeURIComponent",
107+
}),
108+
argumentsArray: [Utils.generateVariableIdentifier(factory, replacedText)],
109+
}),
100110
});
101111
} else {
102112
temporaryStringList.push(requestUriTick);

src/code-templates/_shared/MethodBody/__tests__/PathParameter-test.ts

+35-21
Original file line numberDiff line numberDiff line change
@@ -45,76 +45,90 @@ describe("PathParameter Test", () => {
4545
return getText(expression);
4646
};
4747
test("generateUrlTemplateExpression", () => {
48-
expect(generate("/{a}", [{ in: "path", name: "a", required: true }])).toEqual(`\`/\${params.parameter.a}\`;${EOL}`);
49-
expect(generate("/{a}/", [{ in: "path", name: "a", required: true }])).toEqual(`\`/\${params.parameter.a}/\`;${EOL}`);
50-
expect(generate("/a/{b}", [{ in: "path", name: "b", required: true }])).toEqual(`\`/a/\${params.parameter.b}\`;${EOL}`);
51-
expect(generate("/a/{b}/", [{ in: "path", name: "b", required: true }])).toEqual(`\`/a/\${params.parameter.b}/\`;${EOL}`);
52-
expect(generate("/a/{b}/c", [{ in: "path", name: "b", required: true }])).toEqual(`\`/a/\${params.parameter.b}/c\`;${EOL}`);
53-
expect(generate("/a/{b}/c/", [{ in: "path", name: "b", required: true }])).toEqual(`\`/a/\${params.parameter.b}/c/\`;${EOL}`);
54-
expect(generate("/a/b/{c}", [{ in: "path", name: "c", required: true }])).toEqual(`\`/a/b/\${params.parameter.c}\`;${EOL}`);
55-
expect(generate("/a/b/{c}", [{ in: "path", name: "c", required: true }])).toEqual(`\`/a/b/\${params.parameter.c}\`;${EOL}`);
56-
expect(generate("/a/b/{c}/", [{ in: "path", name: "c", required: true }])).toEqual(`\`/a/b/\${params.parameter.c}/\`;${EOL}`);
57-
expect(generate("/a/b/{c}.json", [{ in: "path", name: "c", required: true }])).toEqual(`\`/a/b/\${params.parameter.c}.json\`;${EOL}`);
48+
expect(generate("/{a}", [{ in: "path", name: "a", required: true }])).toEqual(`\`/\${encodeURIComponent(params.parameter.a)}\`;${EOL}`);
49+
expect(generate("/{a}/", [{ in: "path", name: "a", required: true }])).toEqual(`\`/\${encodeURIComponent(params.parameter.a)}/\`;${EOL}`);
50+
expect(generate("/a/{b}", [{ in: "path", name: "b", required: true }])).toEqual(`\`/a/\${encodeURIComponent(params.parameter.b)}\`;${EOL}`);
51+
expect(generate("/a/{b}/", [{ in: "path", name: "b", required: true }])).toEqual(
52+
`\`/a/\${encodeURIComponent(params.parameter.b)}/\`;${EOL}`,
53+
);
54+
expect(generate("/a/{b}/c", [{ in: "path", name: "b", required: true }])).toEqual(
55+
`\`/a/\${encodeURIComponent(params.parameter.b)}/c\`;${EOL}`,
56+
);
57+
expect(generate("/a/{b}/c/", [{ in: "path", name: "b", required: true }])).toEqual(
58+
`\`/a/\${encodeURIComponent(params.parameter.b)}/c/\`;${EOL}`,
59+
);
60+
expect(generate("/a/b/{c}", [{ in: "path", name: "c", required: true }])).toEqual(
61+
`\`/a/b/\${encodeURIComponent(params.parameter.c)}\`;${EOL}`,
62+
);
63+
expect(generate("/a/b/{c}", [{ in: "path", name: "c", required: true }])).toEqual(
64+
`\`/a/b/\${encodeURIComponent(params.parameter.c)}\`;${EOL}`,
65+
);
66+
expect(generate("/a/b/{c}/", [{ in: "path", name: "c", required: true }])).toEqual(
67+
`\`/a/b/\${encodeURIComponent(params.parameter.c)}/\`;${EOL}`,
68+
);
69+
expect(generate("/a/b/{c}.json", [{ in: "path", name: "c", required: true }])).toEqual(
70+
`\`/a/b/\${encodeURIComponent(params.parameter.c)}.json\`;${EOL}`,
71+
);
5872
expect(generate("/{a}.json/{a}.json/{a}.json", [{ in: "path", name: "a", required: true }])).toEqual(
59-
`\`/\${params.parameter.a}.json/\${params.parameter.a}.json/\${params.parameter.a}.json\`;${EOL}`,
73+
`\`/\${encodeURIComponent(params.parameter.a)}.json/\${encodeURIComponent(params.parameter.a)}.json/\${encodeURIComponent(params.parameter.a)}.json\`;${EOL}`,
6074
);
6175
expect(generate("/.json.{a}.json/{a}.json.{a}", [{ in: "path", name: "a", required: true }])).toEqual(
62-
`\`/.json.\${params.parameter.a}.json/\${params.parameter.a}.json.\${params.parameter.a}\`;${EOL}`,
76+
`\`/.json.\${encodeURIComponent(params.parameter.a)}.json/\${encodeURIComponent(params.parameter.a)}.json.\${encodeURIComponent(params.parameter.a)}\`;${EOL}`,
6377
);
6478

6579
expect(
6680
generate("/{a}/{b}", [
6781
{ in: "path", name: "a", required: true },
6882
{ in: "path", name: "b", required: true },
6983
]),
70-
).toBe(`\`/\${params.parameter.a}/\${params.parameter.b}\`;${EOL}`);
84+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/\${encodeURIComponent(params.parameter.b)}\`;${EOL}`);
7185
expect(
7286
generate("/{a}/{b}/", [
7387
{ in: "path", name: "a", required: true },
7488
{ in: "path", name: "b", required: true },
7589
]),
76-
).toBe(`\`/\${params.parameter.a}/\${params.parameter.b}/\`;${EOL}`);
90+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/\${encodeURIComponent(params.parameter.b)}/\`;${EOL}`);
7791
expect(
7892
generate("/{a}/{b}/c", [
7993
{ in: "path", name: "a", required: true },
8094
{ in: "path", name: "b", required: true },
8195
]),
82-
).toBe(`\`/\${params.parameter.a}/\${params.parameter.b}/c\`;${EOL}`);
96+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/\${encodeURIComponent(params.parameter.b)}/c\`;${EOL}`);
8397
expect(
8498
generate("/{a}/{b}/c/", [
8599
{ in: "path", name: "a", required: true },
86100
{ in: "path", name: "b", required: true },
87101
]),
88-
).toBe(`\`/\${params.parameter.a}/\${params.parameter.b}/c/\`;${EOL}`);
102+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/\${encodeURIComponent(params.parameter.b)}/c/\`;${EOL}`);
89103
expect(
90104
generate("/{a}/b/{c}", [
91105
{ in: "path", name: "a", required: true },
92106
{ in: "path", name: "c", required: true },
93107
]),
94-
).toBe(`\`/\${params.parameter.a}/b/\${params.parameter.c}\`;${EOL}`);
108+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/b/\${encodeURIComponent(params.parameter.c)}\`;${EOL}`);
95109
expect(
96110
generate("/{a}/b/{c}/", [
97111
{ in: "path", name: "a", required: true },
98112
{ in: "path", name: "c", required: true },
99113
]),
100-
).toBe(`\`/\${params.parameter.a}/b/\${params.parameter.c}/\`;${EOL}`);
114+
).toBe(`\`/\${encodeURIComponent(params.parameter.a)}/b/\${encodeURIComponent(params.parameter.c)}/\`;${EOL}`);
101115
expect(
102116
generate("/a/{b}/{c}", [
103117
{ in: "path", name: "b", required: true },
104118
{ in: "path", name: "c", required: true },
105119
]),
106-
).toBe(`\`/a/\${params.parameter.b}/\${params.parameter.c}\`;${EOL}`);
120+
).toBe(`\`/a/\${encodeURIComponent(params.parameter.b)}/\${encodeURIComponent(params.parameter.c)}\`;${EOL}`);
107121
expect(
108122
generate("/a/{b}/{c}/", [
109123
{ in: "path", name: "b", required: true },
110124
{ in: "path", name: "c", required: true },
111125
]),
112-
).toBe(`\`/a/\${params.parameter.b}/\${params.parameter.c}/\`;${EOL}`);
126+
).toBe(`\`/a/\${encodeURIComponent(params.parameter.b)}/\${encodeURIComponent(params.parameter.c)}/\`;${EOL}`);
113127
expect(
114128
generate("/a/{b}...{c}/", [
115129
{ in: "path", name: "b", required: true },
116130
{ in: "path", name: "c", required: true },
117131
]),
118-
).toBe(`\`/a/\${params.parameter.b}...\${params.parameter.c}/\`;${EOL}`);
132+
).toBe(`\`/a/\${encodeURIComponent(params.parameter.b)}...\${encodeURIComponent(params.parameter.c)}/\`;${EOL}`);
119133
});
120134
});

test/__tests__/class/__snapshots__/argo-rollout-test.ts.snap

+10-10
Original file line numberDiff line numberDiff line change
@@ -3859,7 +3859,7 @@ export class Client<RequestOption> {
38593859
}, option);
38603860
}
38613861
public async RolloutService_ListRolloutInfos(params: Params$RolloutService_ListRolloutInfos, option?: RequestOption): Promise<Response$RolloutService_ListRolloutInfos$Status$200["application/json"]> {
3862-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/info\`;
3862+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/info\`;
38633863
const headers = {
38643864
Accept: "application/json"
38653865
};
@@ -3870,7 +3870,7 @@ export class Client<RequestOption> {
38703870
}, option);
38713871
}
38723872
public async RolloutService_WatchRolloutInfos(params: Params$RolloutService_WatchRolloutInfos, option?: RequestOption): Promise<Response$RolloutService_WatchRolloutInfos$Status$200["application/json"]> {
3873-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/info/watch\`;
3873+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/info/watch\`;
38743874
const headers = {
38753875
Accept: "application/json"
38763876
};
@@ -3881,7 +3881,7 @@ export class Client<RequestOption> {
38813881
}, option);
38823882
}
38833883
public async RolloutService_AbortRollout(params: Params$RolloutService_AbortRollout, option?: RequestOption): Promise<Response$RolloutService_AbortRollout$Status$200["application/json"]> {
3884-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/abort\`;
3884+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/abort\`;
38853885
const headers = {
38863886
"Content-Type": "application/json",
38873887
Accept: "application/json"
@@ -3894,7 +3894,7 @@ export class Client<RequestOption> {
38943894
}, option);
38953895
}
38963896
public async RolloutService_GetRolloutInfo(params: Params$RolloutService_GetRolloutInfo, option?: RequestOption): Promise<Response$RolloutService_GetRolloutInfo$Status$200["application/json"]> {
3897-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/info\`;
3897+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/info\`;
38983898
const headers = {
38993899
Accept: "application/json"
39003900
};
@@ -3905,7 +3905,7 @@ export class Client<RequestOption> {
39053905
}, option);
39063906
}
39073907
public async RolloutService_WatchRolloutInfo(params: Params$RolloutService_WatchRolloutInfo, option?: RequestOption): Promise<Response$RolloutService_WatchRolloutInfo$Status$200["application/json"]> {
3908-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/info/watch\`;
3908+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/info/watch\`;
39093909
const headers = {
39103910
Accept: "application/json"
39113911
};
@@ -3916,7 +3916,7 @@ export class Client<RequestOption> {
39163916
}, option);
39173917
}
39183918
public async RolloutService_PromoteRollout(params: Params$RolloutService_PromoteRollout, option?: RequestOption): Promise<Response$RolloutService_PromoteRollout$Status$200["application/json"]> {
3919-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/promote\`;
3919+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/promote\`;
39203920
const headers = {
39213921
"Content-Type": "application/json",
39223922
Accept: "application/json"
@@ -3929,7 +3929,7 @@ export class Client<RequestOption> {
39293929
}, option);
39303930
}
39313931
public async RolloutService_RestartRollout(params: Params$RolloutService_RestartRollout, option?: RequestOption): Promise<Response$RolloutService_RestartRollout$Status$200["application/json"]> {
3932-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/restart\`;
3932+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/restart\`;
39333933
const headers = {
39343934
"Content-Type": "application/json",
39353935
Accept: "application/json"
@@ -3942,7 +3942,7 @@ export class Client<RequestOption> {
39423942
}, option);
39433943
}
39443944
public async RolloutService_RetryRollout(params: Params$RolloutService_RetryRollout, option?: RequestOption): Promise<Response$RolloutService_RetryRollout$Status$200["application/json"]> {
3945-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.name}/retry\`;
3945+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.name)}/retry\`;
39463946
const headers = {
39473947
"Content-Type": "application/json",
39483948
Accept: "application/json"
@@ -3955,7 +3955,7 @@ export class Client<RequestOption> {
39553955
}, option);
39563956
}
39573957
public async RolloutService_SetRolloutImage(params: Params$RolloutService_SetRolloutImage, option?: RequestOption): Promise<Response$RolloutService_SetRolloutImage$Status$200["application/json"]> {
3958-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.rollout}/set/\${params.parameter.container}/\${params.parameter.image}/\${params.parameter.tag}\`;
3958+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.rollout)}/set/\${encodeURIComponent(params.parameter.container)}/\${encodeURIComponent(params.parameter.image)}/\${encodeURIComponent(params.parameter.tag)}\`;
39593959
const headers = {
39603960
"Content-Type": "application/json",
39613961
Accept: "application/json"
@@ -3968,7 +3968,7 @@ export class Client<RequestOption> {
39683968
}, option);
39693969
}
39703970
public async RolloutService_UndoRollout(params: Params$RolloutService_UndoRollout, option?: RequestOption): Promise<Response$RolloutService_UndoRollout$Status$200["application/json"]> {
3971-
const url = this.baseUrl + \`/api/v1/rollouts/\${params.parameter.namespace}/\${params.parameter.rollout}/undo/\${params.parameter.revision}\`;
3971+
const url = this.baseUrl + \`/api/v1/rollouts/\${encodeURIComponent(params.parameter.namespace)}/\${encodeURIComponent(params.parameter.rollout)}/undo/\${encodeURIComponent(params.parameter.revision)}\`;
39723972
const headers = {
39733973
"Content-Type": "application/json",
39743974
Accept: "application/json"

0 commit comments

Comments
 (0)