oav/lib/apiScenario/swaggerAnalyzer.ts

133 строки
5.2 KiB
TypeScript

import { JSONPath } from "jsonpath-plus";
import { inject, injectable } from "inversify";
import _ from "lodash";
import { TYPES } from "../inversifyUtils";
import { FileLoaderOption, FileLoader } from "../swagger/fileLoader";
import { JsonLoader, JsonLoaderOption } from "../swagger/jsonLoader";
import { SwaggerLoader, SwaggerLoaderOption } from "../swagger/swaggerLoader";
import { Path, SwaggerSpec, Schema, LowerHttpMethods, Operation } from "../swagger/swaggerTypes";
import { AjvSchemaValidator } from "../swaggerValidator/ajvSchemaValidator";
import { SchemaValidator } from "../swaggerValidator/schemaValidator";
import { allOfTransformer } from "../transform/allOfTransformer";
import { getTransformContext, TransformContext } from "../transform/context";
import { discriminatorTransformer } from "../transform/discriminatorTransformer";
import { noAdditionalPropertiesTransformer } from "../transform/noAdditionalPropertiesTransformer";
import { referenceFieldsTransformer } from "../transform/referenceFieldsTransformer";
import { resolveNestedDefinitionTransformer } from "../transform/resolveNestedDefinitionTransformer";
import { xmsPathsTransformer } from "../transform/xmsPathsTransformer";
import { applyGlobalTransformers, applySpecTransformers } from "../transform/transformer";
import { traverseSwagger, traverseSwaggerAsync } from "../transform/traverseSwagger";
import { getProvider } from "../util/utils";
import { ScenarioDefinition } from "./apiScenarioTypes";
import { SchemaSearcher } from "./schemaSearcher";
import { CoverageCalculator, OperationCoverageResult } from "./coverageCalculator";
export interface SwaggerAnalyzerOption
extends FileLoaderOption,
JsonLoaderOption,
SwaggerLoaderOption {
swaggerFilePaths?: string[];
noExternalDependencyResourceType?: boolean;
filerTopLevelResourceType?: boolean;
}
@injectable()
export class SwaggerAnalyzer {
private swaggerSpecs: SwaggerSpec[];
private initialized: boolean = false;
private transformContext: TransformContext;
private schemaValidator: SchemaValidator;
// eslint-disable-next-line @typescript-eslint/explicit-member-accessibility
constructor(
@inject(TYPES.opts) private opts: SwaggerAnalyzerOption,
public jsonLoader: JsonLoader,
private swaggerLoader: SwaggerLoader,
private fileLoader: FileLoader
) {
this.swaggerSpecs = [];
this.schemaValidator = new AjvSchemaValidator(this.jsonLoader);
this.transformContext = getTransformContext(this.jsonLoader, this.schemaValidator, [
xmsPathsTransformer,
resolveNestedDefinitionTransformer,
referenceFieldsTransformer,
discriminatorTransformer,
allOfTransformer,
noAdditionalPropertiesTransformer,
]);
}
public calculateOperationCoverage(testDef: ScenarioDefinition): OperationCoverageResult {
return CoverageCalculator.calculateOperationCoverage(testDef, this.swaggerSpecs);
}
public calculateOperationCoverageBySpec(
testDef: ScenarioDefinition
): Map<string, OperationCoverageResult> {
return CoverageCalculator.calculateOperationCoverageBySpec(testDef, this.swaggerSpecs);
}
public getOperations(): { [key: string]: string[] } {
const operations: { [key: string]: string[] } = {};
for (const swaggerSpec of this.swaggerSpecs) {
const allOperationIds = new Set<string>();
traverseSwagger(swaggerSpec, {
onOperation: (operation: Operation, _path: Path, _method: LowerHttpMethods) => {
allOperationIds.add(operation.operationId!);
},
});
operations[swaggerSpec._filePath] = Array.from(allOperationIds);
}
return operations;
}
public async getOperationListPath(): Promise<Path[]> {
const ret: Path[] = [];
for (const swaggerSpec of this.swaggerSpecs) {
await traverseSwaggerAsync(swaggerSpec, {
onPath: async (path, pathTemplate) => {
const resourceProvider = getProvider(pathTemplate);
if (resourceProvider) {
if (path._pathTemplate === `/providers/${resourceProvider}/operations`) {
ret.push(path);
}
}
},
});
}
return ret;
}
public async initialize() {
if (this.initialized) {
throw new Error("Already initialized");
}
for (const swaggerFilePath of this.opts.swaggerFilePaths ?? []) {
const swaggerSpec = await this.swaggerLoader.load(swaggerFilePath);
this.swaggerSpecs.push(swaggerSpec);
applySpecTransformers(swaggerSpec, this.transformContext);
}
applyGlobalTransformers(this.transformContext);
this.initialized = true;
}
public async getAllSecretKey(): Promise<string[]> {
let ret: string[] = [];
const allXmsSecretsPath = '$..[?(@["x-ms-secret"])]~';
for (const swaggerPath of this.opts.swaggerFilePaths ?? []) {
const swagger = JSON.parse(await this.fileLoader.load(swaggerPath));
const allXmsSecretKeys = JSONPath({
path: allXmsSecretsPath,
json: swagger,
});
ret = ret.concat(allXmsSecretKeys);
}
return ret;
}
public findSchemaByJsonPointer(jsonPointer: string, schema: Schema, body?: any) {
return SchemaSearcher.findSchemaByJsonPointer(jsonPointer, schema, this.jsonLoader, body);
}
}