lib/transform/resolveNestedDefinitionTransformer.ts (102 lines of code) (raw):

import { arrayKeywords, keywords, propsKeywords } from "json-schema-traverse"; import { $id } from "../swagger/jsonLoader"; import { Operation, Path, refSelfSymbol, Schema, SwaggerSpec } from "../swagger/swaggerTypes"; import { SpecTransformer, TransformerType } from "./transformer"; import { traverseSwagger } from "./traverseSwagger"; const visited = new WeakSet<Schema>(); export const resolveNestedDefinitionTransformer: SpecTransformer = { type: TransformerType.Spec, transform(spec, { jsonLoader, objSchemas, arrSchemas, primSchemas, allParams }) { const queue = new Array<string>(); const visitNestedDefinitions = (s: Schema | undefined, ref?: string) => { if (s === undefined || s === null || typeof s !== "object") { return; } const schema = jsonLoader.resolveRefObj(s); if (visited.has(schema)) { return; } visited.add(schema); const refSelf = schema === s ? ref : (s as any).$ref; if (refSelf !== undefined) { schema[refSelfSymbol] = refSelf; } if (schema.type === undefined || schema.type === "object") { objSchemas.push(schema); if (schema.discriminator !== undefined && schema[refSelfSymbol] !== undefined) { queue.push(schema[refSelfSymbol]!); } } else if (schema.type === "array") { arrSchemas.push(schema); } else { primSchemas.push(schema); } for (const key of Object.keys(schema)) { const sch = (schema as any)[key]; const refSch = refSelf?.concat("/", key); if (Array.isArray(sch)) { if (key in arrayKeywords) { for (let idx = 0; idx < sch.length; ++idx) { visitNestedDefinitions(sch[idx], refSch?.concat("/", idx.toString())); } } } else if (key in propsKeywords) { if (typeof sch === "object" && sch !== null) { for (const prop of Object.keys(sch)) { visitNestedDefinitions(sch[prop], refSch?.concat("/", prop)); } } } else if (key in keywords) { visitNestedDefinitions(sch, refSch); } } }; const visitParameters = (x: Path | Operation) => { if (x.parameters !== undefined) { for (const p of x.parameters) { const param = jsonLoader.resolveRefObj(p); if (param.in === "body") { visitNestedDefinitions(param.schema); } allParams.push(param); } } }; traverseSwagger(spec, { onPath: visitParameters, onOperation: visitParameters, onResponse: (response) => { visitNestedDefinitions(response.schema); }, }); if (spec.definitions !== undefined) { for (const key of Object.keys(spec.definitions)) { visitNestedDefinitions(spec.definitions[key], `${spec[$id]}#/definitions/${key}`); } } if (spec.parameters !== undefined) { for (const key of Object.keys(spec.parameters)) { spec.parameters[key][refSelfSymbol] = `${spec[$id]}#/parameters/${key}`; } } while (queue.length > 0) { const ref = queue.shift()!; const idx = ref.indexOf("#"); const mockName = idx === -1 ? ref : ref.substr(0, idx); const specFile: SwaggerSpec = jsonLoader.resolveMockedFile(mockName); if (specFile.definitions !== undefined) { for (const key of Object.keys(specFile.definitions)) { const sch = specFile.definitions[key]; if ( sch.allOf?.find(function (s) { return s.$ref === ref; }) !== undefined ) { visitNestedDefinitions(specFile.definitions[key], `${mockName}#/definitions/${key}`); queue.push(`${mockName}#/definitions/${key}`); } } } } }, };