2016-11-19 09:49:15 +03:00
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict' ;
var glob = require ( 'glob' ) ,
path = require ( 'path' ) ,
2016-11-22 08:26:02 +03:00
async = require ( 'async' ) ,
2016-11-19 09:49:15 +03:00
SpecValidator = require ( './lib/specValidator' ) ,
RefParser = require ( 'json-schema-ref-parser' ) ,
swt = require ( 'swagger-tools' ) . specs . v2 ,
2016-11-22 08:26:02 +03:00
finalValidationResult = { validityStatus : true } ;
2016-11-19 09:49:15 +03:00
var cmd = process . argv [ 2 ] ;
exports . printUsage = function printUsage ( ) {
console . log ( '' ) ;
2016-11-20 23:50:28 +03:00
console . log ( 'Usage: node validate.js <command> <spec-path> [--json]\n' ) ;
2016-11-19 09:49:15 +03:00
console . log ( 'Commands:\n' ) ;
console . log ( ' - spec <raw-github-url OR local file-path to the swagger spec> [--json] | Description: Performs semantic validation of the spec.\n' )
2016-11-20 23:50:28 +03:00
console . log ( ' - example <raw-github-url OR local file-path to the swagger spec> [--json] | Description: Performs validation of x-ms-examples and examples present in the spec.' )
console . log ( '\nOptions:\n --json - Provides the json object with detailed status report.\n' )
2016-11-19 09:49:15 +03:00
process . exit ( 1 ) ;
}
if ( cmd === '-h' || cmd === '--help' || cmd === 'help' ) {
exports . printUsage ( ) ;
}
var specPath = process . argv [ 3 ] ;
var jsonOutput = process . argv [ 4 ] ;
if ( cmd !== 'spec' && cmd !== 'example' ) {
if ( cmd ) console . error ( ` ${ cmd } is not a valid command. ` )
exports . printUsage ( ) ;
}
2016-11-20 23:39:25 +03:00
if ( ! specPath || ( specPath && typeof specPath . valueOf ( ) !== 'string' ) ) {
console . error ( ` <spec-path> (raw-github url or a local file path to the swagger spec) is required and must be of type string. ` ) ;
2016-11-19 09:49:15 +03:00
exports . printUsage ( ) ;
}
2016-11-20 23:39:25 +03:00
//If the spec path is a url starting with https://github then let us auto convert it to an https://raw.githubusercontent url.
if ( specPath . startsWith ( 'https://github' ) ) {
console . warn ( 'Warning: Converting the github url to raw github user content url.' ) ;
specPath = specPath . replace ( /^https:\/\/(github.com)(.*)blob\/(.*)/ig , 'https://raw.githubusercontent.com$2$3' ) ;
}
2016-11-19 09:49:15 +03:00
2016-11-22 08:26:02 +03:00
function updateEndResultOfSingleValidation ( validator ) {
if ( validator . specValidationResult . validityStatus ) console . log ( '\n> No Errors were found.' ) ;
if ( ! validator . specValidationResult . validityStatus ) {
finalValidationResult . validityStatus = validator . specValidationResult . validityStatus ;
}
return ;
}
var validator ;
function validateSingleSpec ( singleSpecPath , callback ) {
if ( cmd === 'example' ) {
console . log ( ` \n > Validating "examples" and "x-ms-examples" in ${ singleSpecPath } : \n ` ) ;
validator = new SpecValidator ( singleSpecPath ) ;
finalValidationResult [ singleSpecPath ] = validator . specValidationResult ;
validator . validateDataModels ( function ( err , result ) {
updateEndResultOfSingleValidation ( validator ) ;
return callback ( null ) ;
} ) ;
} else if ( cmd === 'spec' ) {
console . log ( ` \n > Semantically validating ${ singleSpecPath } : \n ` ) ;
validator = new SpecValidator ( singleSpecPath ) ;
finalValidationResult [ singleSpecPath ] = validator . specValidationResult ;
validator . validateSpec ( function ( err , result ) {
updateEndResultOfSingleValidation ( validator ) ;
return callback ( null ) ;
} ) ;
}
}
async . waterfall ( [
function ( callback ) {
if ( specPath . match ( /.*composite.*/ig ) !== null ) {
RefParser . bundle ( specPath , function ( bundleErr , bundleResult ) {
if ( bundleErr ) {
let msg = ` Error occurred in parsing the spec " ${ specPath } ". \t ${ bundleErr . message } . ` ;
bundleErr . code = 'PARSE_SPEC_ERROR' ;
bundleErr . message = msg ;
console . log ( ` ${ bundleErr . code } - ${ bundleErr . message } ` ) ;
throw bundleErr ;
}
return callback ( null , bundleResult . documents ) ;
} ) ;
} else {
return callback ( null , undefined ) ;
}
} ,
function ( docs , callback ) {
if ( docs ) {
async . eachSeries ( docs , function ( doc , loopCallback ) {
let basePath = path . dirname ( specPath ) ;
if ( doc . startsWith ( '.' ) ) {
doc = doc . substring ( 1 ) ;
}
2016-11-22 08:36:56 +03:00
let individualPath = '' ;
if ( doc . startsWith ( 'http' ) ) {
individualPath = doc ;
} else {
individualPath = basePath + doc ;
}
2016-11-22 08:26:02 +03:00
return validateSingleSpec ( individualPath , loopCallback ) ;
} , function ( err ) {
return callback ( null , false ) ; //this callback is called after the eachSeries(for) loopis over.
} ) ;
} else {
return callback ( null , true ) ; //this callback is called when the given spec is not a composite spec.
}
} ,
function ( isNonCompositeSpec , callback ) {
if ( isNonCompositeSpec ) {
return validateSingleSpec ( specPath , callback ) ;
} else {
return callback ( null ) ;
}
}
] , function ( err , result ) {
2016-11-19 09:49:15 +03:00
if ( jsonOutput && jsonOutput === '--json' ) {
2016-11-20 14:14:06 +03:00
console . log ( '\n> Detailed Validation Result:\n' )
2016-11-19 09:49:15 +03:00
console . dir ( finalValidationResult , { depth : null , colors : true } ) ;
}
console . log ( '\n> Validation Complete.' ) ;
2016-11-22 08:26:02 +03:00
if ( ! finalValidationResult . validityStatus ) process . exit ( 2 ) ;
} ) ;
2016-11-19 09:49:15 +03:00
2016-11-20 14:14:06 +03:00
exports = module . exports ;