Unverified Commit ef026f16 authored by Károly Erdős's avatar Károly Erdős Committed by GitHub
Browse files

Merge pull request #6 from elixir-europe/add_cli_to_validator

Add command line interface
parents 763bf21b 66aca49c
......@@ -10,6 +10,10 @@ const addFormats = require("ajv-formats");
const request = require("request-promise");
const AppError = require("./model/application-error");
const devMode = 0;
console.debug = devMode ? console.debug : () => { };
/**
*
* Wraps the generic validator, outputs errors in custom format.
......
const runValidation = require("../validator");
const logger = require("../winston");
const fs = require("fs");
const {log_error, log_info } = require("../utils/logger");
class BioValidatorCLI {
constructor(pathToSchema, pathToJson) {
this.pathToSchema = pathToSchema
this.pathToJson = pathToJson
}
read_schema(pathToSchema) {
if (fs.existsSync(pathToSchema)) {
let schemaStr = fs.readFileSync(pathToSchema, 'utf-8')
return JSON.parse(schemaStr)
} else {
log_error("File '" + pathToSchema + "' does not exist!");
process.exit(1);
}
}
read_json(pathToJson) {
if (fs.existsSync(pathToJson)) {
let jsonStr = fs.readFileSync(pathToJson, 'utf-8')
return JSON.parse(jsonStr)
} else {
log_error("File '" + pathToJson + "' does not exist!");
process.exit(1);
}
}
validate() {
this.inputSchema = this.read_schema(this.pathToSchema)
this.jsonToValidate = this.read_json(this.pathToJson)
if (this.inputSchema && this.jsonToValidate) {
runValidation(this.inputSchema, this.jsonToValidate).then((output) => {
logger.log("silly", "Sent validation results.");
this.process_output(output);
}).catch((error) => {
console.error("console error: " + error);
logger.log("error", error);
});
} else {
let appError = "Something is missing, both schema and object are required to execute validation.";
log_error(appError);
}
}
process_output(output) {
if (output.length === 0) {
log_info("No validation errors reported.");
} else {
log_error("The validation process has found the following error(s):\n")
log_error(this.error_report(output));
}
console.log("Validation finished.");
}
error_report(jsonErrors) {
let errorOutput = "";
jsonErrors.forEach( (errorObject) => {
const dataPath = errorObject.dataPath;
const errors = errorObject.errors;
let errorStr = "";
errors.forEach( (error) => {
errorStr = errorStr.concat("\n\t", error);
})
errorOutput = errorOutput.concat(dataPath + errorStr + "\n");
})
return errorOutput;
}
}
module.exports = BioValidatorCLI;
// Original: https://github.com/Marak/colors.js/blob/master/lib/styles.js
const styleCodes = {
// Reset all styles.
reset: [0, 0],
// Text styles.
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29],
// Foregound classic colours.
fgBlack: [30, 39],
fgRed: [31, 39],
fgGreen: [32, 39],
fgYellow: [33, 39],
fgBlue: [34, 39],
fgMagenta: [35, 39],
fgCyan: [36, 39],
fgWhite: [37, 39],
fgGray: [90, 39],
// Foreground bright colours.
fgBrightRed: [91, 39],
fgBrightGreen: [92, 39],
fgBrightYellow: [93, 39],
fgBrightBlue: [94, 39],
fgBrightMagenta: [95, 39],
fgBrightCyan: [96, 39],
fgBrightWhite: [97, 39],
// Background basic colours.
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
bgGray: [100, 49],
bgGrey: [100, 49],
// Background bright colours.
bgBrightRed: [101, 49],
bgBrightGreen: [102, 49],
bgBrightYellow: [103, 49],
bgBrightBlue: [104, 49],
bgBrightMagenta: [105, 49],
bgBrightCyan: [106, 49],
bgBrightWhite: [107, 49],
};
// This object will contain the string representation for all style codes.
const styles = {};
// Loop over all the style codes and assign them to the `styles` object.
//
// The a `styleCode` in the `styleCodes` object consists of two numbers:
// Index 0: The opening style code (In HTML this can be the opening <b> tag).
// Index 1: The closing style code (In HTML this can be the closing </b> tag).
for (let styleCode of Object.keys(styleCodes)) {
styles[styleCode] = {
open: `\x1B[${styleCodes[styleCode][0]}m`,
close: `\x1B[${styleCodes[styleCode][1]}m`,
};
}
const errorOpen = styles.bold.open + styles.fgRed.open + styles.bgBlack.open;
const resetText = styles.reset.close; // Close everything
const normalText = styles.bold.open + styles.fgGreen.open + styles.bgBlack.open;
module.exports = {errorOpen, normalText, resetText};
......@@ -30,7 +30,7 @@ function runValidation(inputSchema, inputObject) {
return new Promise((resolve, reject) => {
validator.validate(inputSchema, inputObject)
.then((validationResult) => {
if (validationResult.length == 0) {
if (validationResult.length === 0) {
resolve([]);
} else {
let ajvErrors = [];
......
const BioValidatorCLI = require("../src/cli/bio-validator-cli")
test("Using wrong parameters results with error", () => {
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
const schema = "schema/not_exists.json";
const json = "json/not_exists.json";
const cli = new BioValidatorCLI(schema, json);
cli.validate();
expect(mockExit).toHaveBeenCalledWith(1);
mockExit.mockRestore();
});
test( "Invalid JSON should result with validation error", () => {
const schema = "test/resources/cli/test_schema.json";
const json = "test/resources/cli/invalid.json";
const cli = new BioValidatorCLI(schema, json);
const jsonErrors = [
{
"dataPath": ".alias",
"errors": [
"should have required property 'alias'"
]
},
{
"dataPath": ".taxonId",
"errors": [
"should have required property 'taxonId'"
]
}
]
const expectedErrorOutput = ".alias\n" +
"\tshould have required property 'alias'\n" +
".taxonId\n" +
"\tshould have required property 'taxonId'\n";
let errorOutput = cli.error_report(jsonErrors);
expect(errorOutput).toBeDefined();
expect(errorOutput).toEqual(expectedErrorOutput)
});
......@@ -3,10 +3,10 @@ const BioValidator = require('../src/bio-validator');
const IsValidTaxonomy = require('../src/keywords/isvalidtaxonomy');
test("valid taxonomy expression should pass the validation", () => {
let inputSchema = fs.readFileSync("examples/schemas/isValidTaxonomy-schema.json");
let inputSchema = fs.readFileSync("examples/schemas/isValidTaxonomy-schema.json", "utf-8");
let jsonSchema = JSON.parse(inputSchema);
let inputObj = fs.readFileSync("examples/objects/isValidTaxonomy.json");
let inputObj = fs.readFileSync("examples/objects/isValidTaxonomy.json", "utf-8");
let jsonObj = JSON.parse(inputObj);
const schemaValidator = new BioValidator(
......@@ -21,10 +21,10 @@ test("valid taxonomy expression should pass the validation", () => {
});
test("invalid taxonomy expresson should return an error", () => {
let inputSchema = fs.readFileSync("examples/schemas/isValidTaxonomy-schema.json");
let inputSchema = fs.readFileSync("examples/schemas/isValidTaxonomy-schema.json", "utf-8");
let jsonSchema = JSON.parse(inputSchema);
let inputObj = fs.readFileSync("examples/objects/isInvalidTaxonomy.json");
let inputObj = fs.readFileSync("examples/objects/isInvalidTaxonomy.json", "utf-8");
let jsonObj = JSON.parse(inputObj);
const schemaValidator = new BioValidator(
......
{"disease": "glioblastoma",
"disease_id": "MONDO:0018177"
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"alias": {
"description": "A sample unique identifier in a submission.",
"type": "string"
},
"taxonId": {
"description": "The taxonomy id for the sample species.",
"type": "integer"
},
"taxon": {
"description": "The taxonomy name for the sample species.",
"type": "string"
},
"releaseDate": {
"description": "Date from which this sample is released publicly.",
"type": "string",
"format": "date"
},
"disease": {
"description": "The disease for the sample species.",
"type": "string"
},
"disease_id": {
"description": "The ontology id for the disease sample species.",
"type": "string",
"graph_restriction": {
"ontologies": ["obo:mondo", "obo:efo"],
"classes": ["MONDO:0000001", "PATO:0000461"],
"relations": ["rdfs:subClassOf"],
"direct": false,
"include_self": true
}
}
},
"required": ["alias", "taxonId"]
}
{
"alias": "MA456",
"taxonId": 9606,
"disease": "glioblastoma",
"disease_id": "MONDO:0018177"
}
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
function get_usage() {
let helpText = "\nBio-validator CLI (Command Line Interface)\n";
helpText = helpText.concat("usage: node ./validator-cli.js [--schema=path/to/schema] [--json=path/to/json]")
return helpText
}
function print_help() {
console.log(get_usage())
}
const argv = yargs(hideBin(process.argv))
.usage(get_usage())
.demandOption(['schema', 'json'])
.alias('s', 'schema')
.alias('j', 'json')
.describe('schema', 'path to the schema file')
.describe('json', 'path to the json file to validate')
.example('node ./validator-cli.js --json=valid.json --schema=test_schema.json',
'Validates \'valid.json\' with \'test_schema.json\'.')
.argv
const BioValidatorCLI = require("./src/cli/bio-validator-cli");
const {log_error} = require("./src/utils/logger");
let schema = argv["schema"]
let json = argv["json"]
let isParameterMissing = false;
if (!schema || schema === "" || typeof schema === "boolean") {
log_error("Schema parameter or its value is missing!");
isParameterMissing = true;
}
if (!json || json === "" || typeof json === "boolean") {
log_error("Json parameter or its value is missing!");
isParameterMissing = true;
}
if (isParameterMissing || argv["help"]) {
print_help()
} else {
const bioValidator = new BioValidatorCLI(schema, json);
bioValidator.validate()
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment