src/cli.js
// Shebang will be added by webpack
//#!/usr/bin/env node --harmony
/**
* Command Line Interface for the validator
*/
const
VERSION = require('../package.json').version,
program = require('commander'),
{ validateFile, validateExample, validateExamplesByMap } = require('./index');
// FOR AUTOMATED TESTS
const ENV_TEST = process.env.OPENAPI_EXAMPLES_VALIDATOR_TESTS === 'true';
// DEFINE CLI
program
.version(VERSION)
.arguments('<filepath>')
.description('Validate embedded examples in OpenAPI-specs (JSON and YAML supported).\n'
+ ' To validate external examples, use the `-s` and `-e` option.\n'
+ ' To pass a mapping-file, to validate multiple external examples, use the `-m` option.')
.option('-s, --schema-jsonpath <schema-jsonpath>', 'Path to OpenAPI-schema, to validate the example file against')
.option('-e, --example-filepath <example-filepath>', 'file path to example file, to be validated')
.option('-m, --mapping-filepath <mapping-filepath>', 'file path to map, containing schema-paths as key and the'
+ ' file-path(s) to examples as value. If wildcards are used, the parameter has to be put in quotes.')
.option('-c, --cwd-to-mapping-file', "changes to the directory of the mapping-file, before resolving the example's"
+ ' paths. Use this option, if your mapping-files use relative paths for the examples')
.option('-n, --no-additional-properties', 'don\'t allow properties that are not described in the schema')
.option('-r, --all-properties-required', 'make all the properties in the schema required')
.option('-o, --ignore-formats <ignored-formats...>', 'Datatype formats to ignore '
+ '(to prevent "unknown format" message in the error-console.)')
.action(processAction);
program.on('--help', () => {
console.log('\n\n Example for external example-file:\n');
console.log(' $ openapi-examples-validator -s $.paths./.get.responses.200.schema -e example.json'
+ ' openapi-spec.json\n\n');
});
// Execute and export promise (for automated tests)
module.exports = program.parseAsync(process.argv);
// IMPLEMENTATION DETAILS
async function processAction(filepath, options) {
const { schemaJsonpath, exampleFilepath, mappingFilepath, cwdToMappingFile, allPropertiesRequired } = options,
noAdditionalProperties = !options.additionalProperties,
ignoreFormats = _prepareIgnoreFormats(options.ignoreFormats);
let result;
if (mappingFilepath) {
console.log('Validating with mapping file');
result = await validateExamplesByMap(filepath, mappingFilepath, {
cwdToMappingFile,
noAdditionalProperties,
ignoreFormats,
allPropertiesRequired
});
} else if (schemaJsonpath && exampleFilepath) {
console.log('Validating single external example');
result = await validateExample(filepath, schemaJsonpath, exampleFilepath, {
noAdditionalProperties,
ignoreFormats,
allPropertiesRequired
});
} else {
console.log('Validating examples');
result = await validateFile(filepath, {
noAdditionalProperties,
ignoreFormats,
allPropertiesRequired
});
}
_handleResult(result);
}
function _handleResult(result) {
const noExit = ENV_TEST;
_printStatistics(result.statistics);
if (result.valid) {
process.stdout.write('\nNo errors found.\n\n');
!noExit && process.exit(0);
return;
}
process.stdout.write('\nErrors found.\n\n');
process.stderr.write(JSON.stringify(result.errors, null, ' '));
!noExit && process.exit(1);
}
function _printStatistics(statistics) {
const {
schemasWithExamples,
examplesWithoutSchema,
examplesTotal,
matchingFilePathsMapping
} = statistics,
strStatistics = [
`Schemas with examples found: ${ schemasWithExamples }`,
`Examples without schema found: ${ examplesWithoutSchema }`,
`Total examples found: ${ examplesTotal }`
];
if (matchingFilePathsMapping != null) {
strStatistics.push(`Matching mapping files found: ${ matchingFilePathsMapping }`);
}
process.stdout.write(`${ strStatistics.join('\n') }\n`);
}
function _prepareIgnoreFormats(ignoreFormats) {
if (ignoreFormats == null || !Array.isArray(ignoreFormats)) { return ignoreFormats; }
if (ignoreFormats.length !== 1) { return ignoreFormats; }
// If only one argument has been passed, with all formats separated by newlines
if (ignoreFormats[0].indexOf('\n') === -1) { return ignoreFormats; }
return ignoreFormats[0].split('\n').filter(entry => !entry.match(/^\s*$/));
}