lib/swagger/swaggerLoader.ts (114 lines of code) (raw):

import { relative as pathRelative, dirname } from "path"; import { inject, injectable } from "inversify"; import { TYPES } from "../inversifyUtils"; import { traverseSwagger } from "../transform/traverseSwagger"; import { xmsExamples } from "../util/constants"; import { getProviderFromSpecPath } from "../util/utils"; import { FileLoader, FileLoaderOption } from "./fileLoader"; import { JsonLoader, JsonLoaderOption } from "./jsonLoader"; import { Loader, setDefaultOpts } from "./loader"; import { SuppressionLoader, SuppressionLoaderOption } from "./suppressionLoader"; import { SwaggerExample, SwaggerSpec } from "./swaggerTypes"; export interface SwaggerLoaderOption extends SuppressionLoaderOption, JsonLoaderOption, FileLoaderOption { setFilePath?: boolean; } export interface ExampleUpdateEntry { swaggerPath: string; operationId: string; exampleName: string; exampleFilePath: string; exampleContent: SwaggerExample; } @injectable() export class SwaggerLoader implements Loader<SwaggerSpec> { public constructor( @inject(TYPES.opts) private opts: SwaggerLoaderOption, private suppressionLoader: SuppressionLoader, private jsonLoader: JsonLoader, private siblingsJsonLoader: JsonLoader, private fileLoader: FileLoader ) { setDefaultOpts(opts, { setFilePath: true, }); } public getResolvedJsonLoader() { return this.siblingsJsonLoader; } // TODO reportError public async load(specFilePath: string, keepRefSiblings?: boolean): Promise<SwaggerSpec> { const swaggerSpec = keepRefSiblings ? ((await (this.siblingsJsonLoader.load( specFilePath, false, true ) as unknown)) as SwaggerSpec) : ((await (this.jsonLoader.load(specFilePath) as unknown)) as SwaggerSpec); if (this.opts.setFilePath) { const pathProvider = getProviderFromSpecPath(this.fileLoader.resolvePath(specFilePath)); swaggerSpec._filePath = this.fileLoader.relativePath(specFilePath); swaggerSpec._providerNamespace = pathProvider ? pathProvider.provider : "unknown"; } await this.suppressionLoader.load(swaggerSpec); return swaggerSpec; } public async updateSwaggerAndExamples(entries: ExampleUpdateEntry[]) { const swaggerPaths = new Set<string>(); const examplePaths = new Set<string>(); const entriesGroupByOperationId = new Map<string, ExampleUpdateEntry[]>(); for (const entry of entries) { swaggerPaths.add(entry.swaggerPath); if (examplePaths.has(entry.exampleFilePath)) { throw new Error(`Duplicated example path: ${entry.exampleFilePath}`); } examplePaths.add(entry.exampleFilePath); let entriesGroup = entriesGroupByOperationId.get(entry.operationId); if (entriesGroup === undefined) { entriesGroup = []; entriesGroupByOperationId.set(entry.operationId, entriesGroup); } entriesGroup.push(entry); } const toWait: Array<Promise<void>> = []; for (const swaggerPath of swaggerPaths) { const fileContent = await this.fileLoader.load(swaggerPath); const swaggerSpec = JSON.parse(fileContent) as SwaggerSpec; traverseSwagger(swaggerSpec, { onOperation: (operation) => { const operationId = operation.operationId ?? ""; const entriesGroup = entriesGroupByOperationId.get(operationId); if (entriesGroup === undefined) { return; } let examples = operation[xmsExamples]; if (examples === undefined) { examples = {}; operation[xmsExamples] = examples; } for (const entry of entriesGroup) { let path = pathRelative(dirname(swaggerPath), entry.exampleFilePath).replace( /\\/g, "/" ); if (!path.startsWith(".")) { path = `./${path}`; } examples[entry.exampleName] = { $ref: path, } as Partial<SwaggerExample> as SwaggerExample; toWait.push( this.fileLoader.writeFile(entry.exampleFilePath, formatJson(entry.exampleContent)) ); } }, }); toWait.push(this.fileLoader.writeFile(swaggerPath, formatJson(swaggerSpec))); } await Promise.all(toWait); } } const formatJson = (obj: any) => { return JSON.stringify(obj, undefined, 2); };