import * as fs from 'fs' ; import * as path from 'path' ; import * as $RefParser from 'json-schema-ref-parser' ; import { OpenAPISchemaValidator } from './openapi.schema.validator' ; import { BasePath } from './base.path' ; import { OpenAPIFrameworkArgs , OpenAPIFrameworkInit , OpenAPIFrameworkVisitor , OpenAPIV3 , } from './types' ; export class OpenAPIFramework { private readonly args : OpenAPIFrameworkArgs ; private readonly loggingPrefix : string = 'openapi.validator: ' ; constructor ( args ) { this . args = args ; } public async initialize ( visitor ) { const args = this . args ; const apiDoc = await this . loadSpec ( args . apiDoc , args . $refParser ) ; const basePathObs = this . getBasePathsFromServers ( apiDoc . servers ) ; const basePaths = Array . from ( basePathObs . reduce ( ( acc , bp ) => { bp . all ( ) . forEach ( ( path ) => acc . add ( path ) ) ; return acc ; } , new Set < string > ( ) ) ) ; const validateApiSpec = 'validateApiSpec' in args ? ! ! args . validateApiSpec : true ; const validator = new OpenAPISchemaValidator ( { version : apiDoc . openapi , validateApiSpec , } ) ; if ( validateApiSpec ) { const apiDocValidation = validator . validate ( apiDoc ) ; if ( apiDocValidation . errors . length ) { console . error ( `${ this . loggingPrefix }Validating schema` ) ; console . error ( `${ this . loggingPrefix }validation errors` , JSON . stringify ( apiDocValidation . errors , null , '  ' ) ) ; throw new Error ( `${ this . loggingPrefix }args.apiDoc was invalid.  See the output.` ) ; } } const getApiDoc = ( ) => { return apiDoc ; } ; this . sortApiDocTags ( apiDoc ) ; if ( visitor . visitApi ) { visitor . visitApi ( { basePaths , getApiDoc , } ) ; } return { apiDoc , basePaths , } ; } private loadSpec ( filePath , $refParser = { mode : 'bundle' } ) { if ( typeof filePath === 'string' ) { const origCwd = process . cwd ( ) ; const absolutePath = path . resolve ( origCwd , filePath ) ; if ( fs . existsSync ( absolutePath ) ) { const doc = $refParser . mode === 'dereference' ? $RefParser . dereference ( absolutePath ) : $RefParser . bundle ( absolutePath ) ; return doc as Promise < OpenAPIV3 . Document > ; } else { throw new Error ( `${ this . loggingPrefix }spec could not be read at ${ filePath }` ) ; } } const doc = $refParser . mode === 'dereference' ? $RefParser . dereference ( filePath ) : $RefParser . bundle ( filePath ) ; return doc as Promise < OpenAPIV3 . Document > ; } private sortApiDocTags ( apiDoc ) { if ( apiDoc && Array . isArray ( apiDoc . tags ) ) { apiDoc . tags . sort ( ( a , b ) : number => { return a . name < b . name ? - 1 : 1 ; } ) ; } } private getBasePathsFromServers ( servers ) { if ( ! servers || servers . length === 0 ) { return [ new BasePath ( { url : '' } ) ] ; } const basePathsMap = { } ; for ( const server of servers ) { const basePath = new BasePath ( server ) ; basePathsMap [ basePath . expressPath ] = basePath ; } return Object . keys ( basePathsMap ) . map ( ( key ) => basePathsMap [ key ] ) ; } }