fork of hey-api/openapi-ts because I need some additional things
1import type { Context } from '../../../ir/context';
2import { buildResourceMetadata } from '../../../openApi/shared/graph/meta';
3import { transformOpenApiSpec } from '../../../openApi/shared/transforms';
4import type { State } from '../../../openApi/shared/types/state';
5import {
6 createFilteredDependencies,
7 createFilters,
8 hasFilters,
9} from '../../../openApi/shared/utils/filter';
10import { buildGraph } from '../../../openApi/shared/utils/graph';
11import { mergeParametersObjects } from '../../../openApi/shared/utils/parameter';
12import { handleValidatorResult } from '../../../openApi/shared/utils/validator';
13import type {
14 OpenApiV3_0_X,
15 ParameterObject,
16 PathItemObject,
17 PathsObject,
18 RequestBodyObject,
19 SecuritySchemeObject,
20} from '../types/spec';
21import { filterSpec } from './filter';
22import { parsePathOperation } from './operation';
23import { parametersArrayToObject, parseParameter } from './parameter';
24import { parseRequestBody } from './requestBody';
25import { parseSchema } from './schema';
26import { parseServers } from './server';
27import { validateOpenApiSpec } from './validate';
28
29export const parseV3_0_X = (context: Context<OpenApiV3_0_X>) => {
30 if (context.config.parser.validate_EXPERIMENTAL) {
31 const result = validateOpenApiSpec(context.spec, context.logger);
32 handleValidatorResult({ context, result });
33 }
34
35 const shouldFilterSpec = hasFilters(context.config.parser.filters);
36 if (shouldFilterSpec) {
37 const filters = createFilters(context.config.parser.filters, context.spec, context.logger);
38 const { graph } = buildGraph(context.spec, context.logger);
39 const { resourceMetadata } = buildResourceMetadata(graph, context.logger);
40 const sets = createFilteredDependencies({
41 filters,
42 logger: context.logger,
43 resourceMetadata,
44 });
45 filterSpec({
46 ...sets,
47 logger: context.logger,
48 preserveOrder: filters.preserveOrder,
49 spec: context.spec,
50 });
51 }
52
53 transformOpenApiSpec({ context });
54
55 const state: State = {
56 ids: new Map(),
57 };
58 const securitySchemesMap = new Map<string, SecuritySchemeObject>();
59
60 // TODO: parser - handle more component types, old parser handles only parameters and schemas
61 if (context.spec.components) {
62 for (const name in context.spec.components.securitySchemes) {
63 const securityOrReference = context.spec.components.securitySchemes[name]!;
64 const securitySchemeObject =
65 '$ref' in securityOrReference
66 ? context.resolveRef<SecuritySchemeObject>(securityOrReference.$ref)
67 : securityOrReference;
68 securitySchemesMap.set(name, securitySchemeObject);
69 }
70
71 for (const name in context.spec.components.parameters) {
72 const $ref = `#/components/parameters/${name}`;
73 const parameterOrReference = context.spec.components.parameters[name]!;
74 const parameter =
75 '$ref' in parameterOrReference
76 ? context.resolveRef<ParameterObject>(parameterOrReference.$ref)
77 : parameterOrReference;
78
79 parseParameter({
80 $ref,
81 context,
82 parameter,
83 });
84 }
85
86 for (const name in context.spec.components.requestBodies) {
87 const $ref = `#/components/requestBodies/${name}`;
88 const requestBodyOrReference = context.spec.components.requestBodies[name]!;
89 const requestBody =
90 '$ref' in requestBodyOrReference
91 ? context.resolveRef<RequestBodyObject>(requestBodyOrReference.$ref)
92 : requestBodyOrReference;
93
94 parseRequestBody({
95 $ref,
96 context,
97 requestBody,
98 });
99 }
100
101 for (const name in context.spec.components.schemas) {
102 const $ref = `#/components/schemas/${name}`;
103 const schema = context.spec.components.schemas[name]!;
104
105 parseSchema({
106 $ref,
107 context,
108 schema,
109 });
110 }
111 }
112
113 parseServers({ context });
114
115 for (const path in context.spec.paths) {
116 if (path.startsWith('x-')) continue;
117 const pathItem = context.spec.paths[path as keyof PathsObject]! as PathItemObject;
118
119 const finalPathItem = pathItem.$ref
120 ? {
121 ...context.resolveRef<PathItemObject>(pathItem.$ref),
122 ...pathItem,
123 }
124 : pathItem;
125
126 const operationArgs: Omit<Parameters<typeof parsePathOperation>[0], 'method' | 'operation'> & {
127 operation: Omit<Parameters<typeof parsePathOperation>[0]['operation'], 'responses'>;
128 } = {
129 context,
130 operation: {
131 description: finalPathItem.description,
132 parameters: parametersArrayToObject({
133 context,
134 parameters: finalPathItem.parameters,
135 }),
136 security: context.spec.security,
137 servers: finalPathItem.servers,
138 summary: finalPathItem.summary,
139 },
140 path: path as `/${string}`,
141 securitySchemesMap,
142 state,
143 };
144
145 if (finalPathItem.delete) {
146 parsePathOperation({
147 ...operationArgs,
148 method: 'delete',
149 operation: {
150 ...operationArgs.operation,
151 ...finalPathItem.delete,
152 parameters: mergeParametersObjects({
153 source: parametersArrayToObject({
154 context,
155 parameters: finalPathItem.delete.parameters,
156 }),
157 target: operationArgs.operation.parameters,
158 }),
159 },
160 });
161 }
162
163 if (finalPathItem.get) {
164 parsePathOperation({
165 ...operationArgs,
166 method: 'get',
167 operation: {
168 ...operationArgs.operation,
169 ...finalPathItem.get,
170 parameters: mergeParametersObjects({
171 source: parametersArrayToObject({
172 context,
173 parameters: finalPathItem.get.parameters,
174 }),
175 target: operationArgs.operation.parameters,
176 }),
177 },
178 });
179 }
180
181 if (finalPathItem.head) {
182 parsePathOperation({
183 ...operationArgs,
184 method: 'head',
185 operation: {
186 ...operationArgs.operation,
187 ...finalPathItem.head,
188 parameters: mergeParametersObjects({
189 source: parametersArrayToObject({
190 context,
191 parameters: finalPathItem.head.parameters,
192 }),
193 target: operationArgs.operation.parameters,
194 }),
195 },
196 });
197 }
198
199 if (finalPathItem.options) {
200 parsePathOperation({
201 ...operationArgs,
202 method: 'options',
203 operation: {
204 ...operationArgs.operation,
205 ...finalPathItem.options,
206 parameters: mergeParametersObjects({
207 source: parametersArrayToObject({
208 context,
209 parameters: finalPathItem.options.parameters,
210 }),
211 target: operationArgs.operation.parameters,
212 }),
213 },
214 });
215 }
216
217 if (finalPathItem.patch) {
218 parsePathOperation({
219 ...operationArgs,
220 method: 'patch',
221 operation: {
222 ...operationArgs.operation,
223 ...finalPathItem.patch,
224 parameters: mergeParametersObjects({
225 source: parametersArrayToObject({
226 context,
227 parameters: finalPathItem.patch.parameters,
228 }),
229 target: operationArgs.operation.parameters,
230 }),
231 },
232 });
233 }
234
235 if (finalPathItem.post) {
236 parsePathOperation({
237 ...operationArgs,
238 method: 'post',
239 operation: {
240 ...operationArgs.operation,
241 ...finalPathItem.post,
242 parameters: mergeParametersObjects({
243 source: parametersArrayToObject({
244 context,
245 parameters: finalPathItem.post.parameters,
246 }),
247 target: operationArgs.operation.parameters,
248 }),
249 },
250 });
251 }
252
253 if (finalPathItem.put) {
254 parsePathOperation({
255 ...operationArgs,
256 method: 'put',
257 operation: {
258 ...operationArgs.operation,
259 ...finalPathItem.put,
260 parameters: mergeParametersObjects({
261 source: parametersArrayToObject({
262 context,
263 parameters: finalPathItem.put.parameters,
264 }),
265 target: operationArgs.operation.parameters,
266 }),
267 },
268 });
269 }
270
271 if (finalPathItem.trace) {
272 parsePathOperation({
273 ...operationArgs,
274 method: 'trace',
275 operation: {
276 ...operationArgs.operation,
277 ...finalPathItem.trace,
278 parameters: mergeParametersObjects({
279 source: parametersArrayToObject({
280 context,
281 parameters: finalPathItem.trace.parameters,
282 }),
283 target: operationArgs.operation.parameters,
284 }),
285 },
286 });
287 }
288 }
289};