Skip to content

Commit fcc3f38

Browse files
authored
fix: pathItem's parameters field support (#48)
* fix: pathItem's parameters field support * fix: Support for parameter overwriting
1 parent 0277a14 commit fcc3f38

File tree

11 files changed

+463
-40
lines changed

11 files changed

+463
-40
lines changed

src/internal/OpenApiTools/Walker/Operation.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ export interface State {
88
[operationId: string]: CodeGenerator.OpenApiOperation;
99
}
1010

11+
type UniqueParameterMap = Record<string, OpenApi.Parameter>;
12+
13+
const uniqParameters = (rawParameters: OpenApi.Parameter[]): OpenApi.Parameter[] => {
14+
const parameterMap = rawParameters.reduce<UniqueParameterMap>((all, parameter) => {
15+
return { ...all, [`${parameter.in}:${parameter.name}`]: parameter };
16+
}, {});
17+
return Object.values(parameterMap);
18+
};
19+
1120
export const create = (rootSchema: OpenApi.Document): State => {
1221
const paths = rootSchema.paths || {};
1322
const state: State = {};
@@ -20,13 +29,15 @@ export const create = (rootSchema: OpenApi.Document): State => {
2029
if (!operation.operationId) {
2130
return;
2231
}
32+
const parameters = [...(pathItem.parameters || []), ...(operation.parameters || [])] as OpenApi.Parameter[];
33+
2334
state[operation.operationId] = {
2435
httpMethod,
2536
requestUri,
2637
comment: [operation.summary, operation.description].filter(Boolean).join(EOL),
2738
deprecated: !!operation.deprecated,
2839
requestBody: operation.requestBody as OpenApi.RequestBody,
29-
parameters: operation.parameters as OpenApi.Parameter[],
40+
parameters: uniqParameters(parameters),
3041
responses: operation.responses as CodeGenerator.OpenApiResponses,
3142
};
3243
});

src/internal/OpenApiTools/Walker/Store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Store {
1616
private state: State.Type;
1717
private operator: Structure.OperatorType;
1818
private getChildByPaths: Structure.GetChildByPaths;
19-
constructor(private factory: Factory.Type, private rootDocument: OpenApi.Document) {
19+
constructor(private factory: Factory.Type, rootDocument: OpenApi.Document) {
2020
this.state = State.createDefaultState(rootDocument);
2121
const { operator, getChildByPaths } = Structure.create();
2222
this.operator = operator;

src/internal/OpenApiTools/components/Operation.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const generateComment = (operation: OpenApi.Operation): string => {
3131
return comments.join(EOL);
3232
};
3333

34-
// 使わない可能性あり
3534
export const generateNamespace = (
3635
entryPoint: string,
3736
currentPoint: string,
@@ -40,6 +39,7 @@ export const generateNamespace = (
4039
parentPath: string,
4140
name: string,
4241
operation: OpenApi.Operation,
42+
pathItemParameters: OpenApi.PathItem["parameters"],
4343
context: ToTypeNode.Context,
4444
converterContext: ConverterContext.Types,
4545
): void => {
@@ -55,7 +55,9 @@ export const generateNamespace = (
5555
deprecated: operation.deprecated,
5656
});
5757

58-
if (operation.parameters) {
58+
const parameters = [...pathItemParameters || [], ...operation.parameters || []];
59+
60+
if (parameters.length > 0) {
5961
const parameterName = "Parameter";
6062
store.addStatement(`${basePath}/Parameter`, {
6163
kind: "interface",
@@ -66,7 +68,7 @@ export const generateNamespace = (
6668
store,
6769
factory,
6870
parameterName,
69-
operation.parameters,
71+
parameters,
7072
context,
7173
converterContext,
7274
),
@@ -136,6 +138,7 @@ export const generateStatements = (
136138
requestUri: string,
137139
httpMethod: string, // PUT POST PATCH
138140
operation: OpenApi.Operation,
141+
pathItemParameters: OpenApi.PathItem["parameters"],
139142
context: ToTypeNode.Context,
140143
converterContext: ConverterContext.Types,
141144
): ts.Statement[] => {
@@ -145,7 +148,8 @@ export const generateStatements = (
145148
throw new Error("not setting operationId\n" + JSON.stringify(operation));
146149
}
147150
store.updateOperationState(httpMethod, requestUri, operationId, {});
148-
if (operation.parameters) {
151+
const parameters = [...pathItemParameters || [], ...operation.parameters || []];
152+
if (parameters.length > 0) {
149153
const parameterName = converterContext.generateParameterName(operationId);
150154
statements.push(
151155
Parameter.generateAliasInterface(
@@ -154,7 +158,7 @@ export const generateStatements = (
154158
store,
155159
factory,
156160
parameterName,
157-
operation.parameters,
161+
parameters,
158162
context,
159163
converterContext,
160164
),

src/internal/OpenApiTools/components/Parameter.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,38 @@ export const generateTypeAlias = (
3636
});
3737
};
3838

39-
export const generatePropertySignature = (
39+
export const generatePropertySignatureObject = (
4040
entryPoint: string,
4141
currentPoint: string,
4242
store: Walker.Store,
4343
factory: Factory.Type,
4444
parameter: OpenApi.Parameter | OpenApi.Reference,
4545
context: ToTypeNode.Context,
4646
converterContext: ConverterContext.Types,
47-
): ts.PropertySignature => {
47+
): { name: string; typeElement: ts.PropertySignature } => {
4848
if (Guard.isReference(parameter)) {
4949
const reference = Reference.generate<OpenApi.Parameter>(entryPoint, currentPoint, parameter);
5050
if (reference.type === "local") {
5151
context.setReferenceHandler(currentPoint, reference);
5252
const localRef = store.getParameter(reference.path);
53-
return factory.PropertySignature.create({
54-
name: converterContext.escapePropertySignatureName(localRef.name),
53+
const name = converterContext.escapePropertySignatureName(localRef.name);
54+
const typeElement = factory.PropertySignature.create({
55+
name: name,
5556
optional: false,
5657
comment: localRef.description,
5758
type: factory.TypeReferenceNode.create({
5859
name: context.resolveReferencePath(currentPoint, reference.path).name,
5960
}),
6061
});
62+
return {
63+
name,
64+
typeElement: typeElement,
65+
};
6166
}
6267
const isPathProperty = reference.data.in === "path";
63-
return factory.PropertySignature.create({
64-
name: converterContext.escapePropertySignatureName(reference.data.name),
68+
const name = converterContext.escapePropertySignatureName(reference.data.name);
69+
const typeElement = factory.PropertySignature.create({
70+
name: name,
6571
optional: isPathProperty ? false : !reference.data.required,
6672
comment: reference.data.description,
6773
type: ToTypeNode.convert(
@@ -73,14 +79,23 @@ export const generatePropertySignature = (
7379
converterContext,
7480
),
7581
});
82+
return {
83+
name,
84+
typeElement: typeElement,
85+
};
7686
}
7787
const isPathProperty = parameter.in === "path";
78-
return factory.PropertySignature.create({
79-
name: converterContext.escapePropertySignatureName(parameter.name),
88+
const name = converterContext.escapePropertySignatureName(parameter.name);
89+
const typeElement = factory.PropertySignature.create({
90+
name: name,
8091
optional: isPathProperty ? false : !parameter.required,
8192
type: ToTypeNode.convert(entryPoint, currentPoint, factory, parameter.schema || { type: "null" }, context, converterContext),
8293
comment: parameter.description,
8394
});
95+
return {
96+
name,
97+
typeElement: typeElement,
98+
};
8499
};
85100

86101
export const generatePropertySignatures = (
@@ -92,9 +107,11 @@ export const generatePropertySignatures = (
92107
context: ToTypeNode.Context,
93108
converterContext: ConverterContext.Types,
94109
): ts.PropertySignature[] => {
95-
return parameters.map(parameter => {
96-
return generatePropertySignature(entryPoint, currentPoint, store, factory, parameter, context, converterContext);
97-
});
110+
const typeElementMap = parameters.reduce<Record<string, ts.PropertySignature>>((all, parameter) => {
111+
const { name, typeElement } = generatePropertySignatureObject(entryPoint, currentPoint, store, factory, parameter, context, converterContext);
112+
return { ...all, [name]: typeElement };
113+
}, {});
114+
return Object.values(typeElementMap);
98115
};
99116

100117
export const generateInterface = (
@@ -103,7 +120,7 @@ export const generateInterface = (
103120
store: Walker.Store,
104121
factory: Factory.Type,
105122
name: string,
106-
parameters: [OpenApi.Parameter | OpenApi.Reference],
123+
parameters: (OpenApi.Parameter | OpenApi.Reference)[],
107124
context: ToTypeNode.Context,
108125
converterContext: ConverterContext.Types,
109126
): ts.InterfaceDeclaration => {

src/internal/OpenApiTools/components/PathItem.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,28 @@ export const generateNamespace = (
2929
comment: Servers.addComment([topComment, pathItem.description], pathItem.servers),
3030
});
3131
if (pathItem.get) {
32-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "GET", pathItem.get, context, converterContext);
32+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "GET", pathItem.get, pathItem.parameters, context, converterContext);
3333
}
3434
if (pathItem.put) {
35-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "PUT", pathItem.put, context, converterContext);
35+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "PUT", pathItem.put, pathItem.parameters,context, converterContext);
3636
}
3737
if (pathItem.post) {
38-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "POST", pathItem.post, context, converterContext);
38+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "POST", pathItem.post, pathItem.parameters, context, converterContext);
3939
}
4040
if (pathItem.delete) {
41-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "DELETE", pathItem.delete, context, converterContext);
41+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "DELETE", pathItem.delete, pathItem.parameters, context, converterContext);
4242
}
4343
if (pathItem.options) {
44-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "OPTIONS", pathItem.options, context, converterContext);
44+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "OPTIONS", pathItem.options, pathItem.parameters, context, converterContext);
4545
}
4646
if (pathItem.head) {
47-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "HEAD", pathItem.head, context, converterContext);
47+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "HEAD", pathItem.head, pathItem.parameters, context, converterContext);
4848
}
4949
if (pathItem.patch) {
50-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "PATCH", pathItem.patch, context, converterContext);
50+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "PATCH", pathItem.patch, pathItem.parameters, context, converterContext);
5151
}
5252
if (pathItem.trace) {
53-
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "TRACE", pathItem.trace, context, converterContext);
53+
Operation.generateNamespace(entryPoint, currentPoint, store, factory, basePath, "TRACE", pathItem.trace, pathItem.parameters, context, converterContext);
5454
}
5555
if (pathItem.parameters) {
5656
Parameters.generateNamespaceWithList(entryPoint, currentPoint, store, factory, pathItem.parameters, context, converterContext);
@@ -70,22 +70,22 @@ export const generateStatements = (
7070
const statements: ts.Statement[][] = [];
7171
if (pathItem.get) {
7272
statements.push(
73-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "GET", pathItem.get, context, converterContext),
73+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "GET", pathItem.get, pathItem.parameters, context, converterContext),
7474
);
7575
}
7676
if (pathItem.put) {
7777
statements.push(
78-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "PUT", pathItem.put, context, converterContext),
78+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "PUT", pathItem.put, pathItem.parameters, context, converterContext),
7979
);
8080
}
8181
if (pathItem.post) {
8282
statements.push(
83-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "POST", pathItem.post, context, converterContext),
83+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "POST", pathItem.post, pathItem.parameters, context, converterContext),
8484
);
8585
}
8686
if (pathItem.delete) {
8787
statements.push(
88-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "DELETE", pathItem.delete, context, converterContext),
88+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "DELETE", pathItem.delete, pathItem.parameters, context, converterContext),
8989
);
9090
}
9191
if (pathItem.options) {
@@ -98,24 +98,25 @@ export const generateStatements = (
9898
requestUri,
9999
"OPTIONS",
100100
pathItem.options,
101+
pathItem.parameters,
101102
context,
102103
converterContext,
103104
),
104105
);
105106
}
106107
if (pathItem.head) {
107108
statements.push(
108-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "HEAD", pathItem.head, context, converterContext),
109+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "HEAD", pathItem.head, pathItem.parameters, context, converterContext),
109110
);
110111
}
111112
if (pathItem.patch) {
112113
statements.push(
113-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "PATCH", pathItem.patch, context, converterContext),
114+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "PATCH", pathItem.patch, pathItem.parameters, context, converterContext),
114115
);
115116
}
116117
if (pathItem.trace) {
117118
statements.push(
118-
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "TRACE", pathItem.trace, context, converterContext),
119+
Operation.generateStatements(entryPoint, currentPoint, store, factory, requestUri, "TRACE", pathItem.trace, pathItem.parameters, context, converterContext),
119120
);
120121
}
121122
// if (pathItem.parameters) {

src/typedef/OpenApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export interface Operation {
246246
description?: string;
247247
externalDocs?: ExternalDocumentation;
248248
operationId?: string;
249-
parameters?: [Parameter | Reference];
249+
parameters?: (Parameter | Reference)[];
250250
requestBody?: RequestBody | Reference;
251251
responses?: Responses;
252252
callbacks?: Record<string, Callback | Reference>;

0 commit comments

Comments
 (0)