fork of hey-api/openapi-ts because I need some additional things
at feat/skip-token 289 lines 8.7 kB view raw
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};