From 9ad3993f19dc904a5ad554ab743924664e3d52b1 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Fri, 4 Jun 2021 14:37:05 +0530 Subject: [PATCH 01/11] Add base for validation * Referencing #25 --- package.json | 1 + validation/schemaMap.json | 4 ++++ validation/validate.js | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 validation/schemaMap.json create mode 100644 validation/validate.js diff --git a/package.json b/package.json index 1a8a1220..a9e09ea0 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "scripts": { "labgen": "node main.js", "validate-lab-descriptor": "node validateDescriptor.js", + "validate-schema": "node validation/validate.js", "build-ds-exp": "node exp.js --env=testing ../", "build-exp": "node exp.js --env=testing ../" }, diff --git a/validation/schemaMap.json b/validation/schemaMap.json new file mode 100644 index 00000000..2a699f45 --- /dev/null +++ b/validation/schemaMap.json @@ -0,0 +1,4 @@ +{ + "posttest.json": "./schemas/quizv2Schema.json", + "pretest.json" : "./schemas/quizv2Schema.json" +} \ No newline at end of file diff --git a/validation/validate.js b/validation/validate.js new file mode 100644 index 00000000..8d960676 --- /dev/null +++ b/validation/validate.js @@ -0,0 +1,43 @@ +const Ajv = require('ajv'); +const path = require('path'); +const schemaMap = require('./schemaMap.json') + +let validateSchema = (input="1", schema="1") => { + console.log("validating " + input + " against " + schema); + console.log("You got validated"); +} + +module.exports.validateSchema = validateSchema; + +/** + * node validation/validate.js + */ +if (require.main === module) { + let json="" + let schema="" + console.log(process.argv.length) + switch(process.argv.length){ + case 2: + console.log('validating all') + validateSchema(); + break; + case 3: + json = process.argv[2]; + json = json.replace('/', '\\') + let n = json.lastIndexOf('\\'); + let jsonKey = json.substring(n + 1); + console.log(json, n) + schema=schemaMap[jsonKey]; + console.log(schema) + validateSchema(json, schema); + break + case 4: + json = path.resolve(process.argv[2]); + schema=path.resolve(process.argv[3]); + validateSchema(json, schema); + break + default: + console.log("Error") + } +} + \ No newline at end of file From aff33f488474f44368bed55ea8c0e34905936b48 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Mon, 7 Jun 2021 13:04:01 +0530 Subject: [PATCH 02/11] Inital yargs implemetnation * schemaMap.json -> schema-map.json --- package-lock.json | 213 +++++++++++++++++- package.json | 3 +- .../{schemaMap.json => schema-map.json} | 0 validation/validate.js | 90 +++++--- 4 files changed, 270 insertions(+), 36 deletions(-) rename validation/{schemaMap.json => schema-map.json} (100%) diff --git a/package-lock.json b/package-lock.json index fa1d751e..d3475399 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "moment": "^2.27.0", "prettier": "^2.0.5", "shelljs": "^0.8.4", - "simple-git": "^2.31.0" + "simple-git": "^2.31.0", + "yargs": "^17.0.1" }, "devDependencies": { "@babel/cli": "^7.12.16", @@ -1168,6 +1169,35 @@ "node": ">=6" } }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1421,6 +1451,14 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1851,6 +1889,14 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -3207,6 +3253,14 @@ "node": ">=0.8" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -4071,6 +4125,41 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4093,6 +4182,39 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", + "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "engines": { + "node": ">=10" + } } }, "dependencies": { @@ -5067,6 +5189,31 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==" }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -5281,6 +5428,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -5618,6 +5770,11 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -6705,6 +6862,11 @@ } } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -7405,6 +7567,31 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7424,6 +7611,30 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", + "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==" } } } diff --git a/package.json b/package.json index a9e09ea0..4f162cc0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "moment": "^2.27.0", "prettier": "^2.0.5", "shelljs": "^0.8.4", - "simple-git": "^2.31.0" + "simple-git": "^2.31.0", + "yargs": "^17.0.1" }, "description": "", "main": "main.js", diff --git a/validation/schemaMap.json b/validation/schema-map.json similarity index 100% rename from validation/schemaMap.json rename to validation/schema-map.json diff --git a/validation/validate.js b/validation/validate.js index 8d960676..63db87af 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -1,11 +1,34 @@ -const Ajv = require('ajv'); -const path = require('path'); -const schemaMap = require('./schemaMap.json') +const Ajv = require("ajv"); +const path = require("path"); +const schemaMap = require("./schema-map.json"); -let validateSchema = (input="1", schema="1") => { - console.log("validating " + input + " against " + schema); - console.log("You got validated"); -} +const argv = require("yargs")(process.argv.slice(2)) + .scriptName("validate") + .usage("$0 [args]") + .option("files", { + type: "array", + desc: "One or more files for validation", + demandOption: true, + }).check((argv) => { + if(argv.files.length === 0){ + throw new Error('Empty Argument: Filenames cannot be empty'); + } + }) + .option("schema-map", { + type: "string", + desc: "The schema map file", + }).alias({ + help: 'h', + version: 'v', + files: 'f', + schemaMap: 's', + }).argv; +console.log(argv); + +let validateSchema = (input = "1", schema = "1") => { + console.log("validating " + input + " against " + schema); + console.log("You got validated"); +}; module.exports.validateSchema = validateSchema; @@ -13,31 +36,30 @@ module.exports.validateSchema = validateSchema; * node validation/validate.js */ if (require.main === module) { - let json="" - let schema="" - console.log(process.argv.length) - switch(process.argv.length){ - case 2: - console.log('validating all') - validateSchema(); - break; - case 3: - json = process.argv[2]; - json = json.replace('/', '\\') - let n = json.lastIndexOf('\\'); - let jsonKey = json.substring(n + 1); - console.log(json, n) - schema=schemaMap[jsonKey]; - console.log(schema) - validateSchema(json, schema); - break - case 4: - json = path.resolve(process.argv[2]); - schema=path.resolve(process.argv[3]); - validateSchema(json, schema); - break - default: - console.log("Error") - } + let json = ""; + let schema = ""; + console.log(process.argv.length); + switch (process.argv.length) { + case 2: + console.log("validating all"); + validateSchema(); + break; + case 3: + json = process.argv[2]; + json = json.replace("/", "\\"); + let n = json.lastIndexOf("\\"); + let jsonKey = json.substring(n + 1); + console.log(json, n); + schema = schemaMap[jsonKey]; + console.log(schema); + validateSchema(json, schema); + break; + case 4: + json = path.resolve(process.argv[2]); + schema = path.resolve(process.argv[3]); + validateSchema(json, schema); + break; + default: + console.log("Error"); + } } - \ No newline at end of file From 126aa6bb5c79219703f8e42ef424887d06f974ac Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 8 Jun 2021 00:41:43 +0530 Subject: [PATCH 03/11] Add initial validation * npm run validate-schema -f prestest.json * npm run validate-schema -f pretest.json posttest.json * npm run validate-schema -f test.json -s ./schemas/quizv2Schema.js --- validation/schema-map.json | 4 +- validation/schemas/quizv2Schema.js | 33 ++++++++++++ validation/validate.js | 84 +++++++++++++++--------------- 3 files changed, 78 insertions(+), 43 deletions(-) create mode 100644 validation/schemas/quizv2Schema.js diff --git a/validation/schema-map.json b/validation/schema-map.json index 2a699f45..aca70695 100644 --- a/validation/schema-map.json +++ b/validation/schema-map.json @@ -1,4 +1,4 @@ { - "posttest.json": "./schemas/quizv2Schema.json", - "pretest.json" : "./schemas/quizv2Schema.json" + "posttest.json": "./schemas/quizv2Schema.js", + "pretest.json" : "./schemas/quizv2Schema.js" } \ No newline at end of file diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js new file mode 100644 index 00000000..dcd762cf --- /dev/null +++ b/validation/schemas/quizv2Schema.js @@ -0,0 +1,33 @@ +module.exports = { + type: "object", + properties: { + version: { type: "integer" }, + questions: { + type: "array", + items: { + type: "object", + properties: { + question: { + type: "string", + }, + answers: { + type: "object", + }, + correctAnswer: { + type: "string", + }, + difficulty: { + type: "string", + }, + explanations: { + type: "object", + }, + }, + additionalProperties: false, + required: ["question", "answers", "correctAnswer", "difficulty"], + }, + }, + }, + required: ["version", "questions"], + additionalProperties: false, +}; diff --git a/validation/validate.js b/validation/validate.js index 63db87af..2691ff45 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -1,7 +1,10 @@ const Ajv = require("ajv"); const path = require("path"); +const fs = require("fs"); const schemaMap = require("./schema-map.json"); +const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true} + const argv = require("yargs")(process.argv.slice(2)) .scriptName("validate") .usage("$0 [args]") @@ -9,57 +12,56 @@ const argv = require("yargs")(process.argv.slice(2)) type: "array", desc: "One or more files for validation", demandOption: true, - }).check((argv) => { - if(argv.files.length === 0){ - throw new Error('Empty Argument: Filenames cannot be empty'); + }) + .check((argv) => { + if (argv.files.length === 0) { + throw new Error("Empty Argument: Filenames cannot be empty"); } + return true; }) .option("schema-map", { type: "string", desc: "The schema map file", - }).alias({ - help: 'h', - version: 'v', - files: 'f', - schemaMap: 's', + }) + .alias({ + help: "h", + version: "v", + files: "f", + "schema-map": "s", }).argv; -console.log(argv); let validateSchema = (input = "1", schema = "1") => { - console.log("validating " + input + " against " + schema); - console.log("You got validated"); + let validationSchema = require(schema); + let validate = ajv.compile(validationSchema); + let valid = validate(input); + valid + ? console.log("Validated", valid) + : console.log("Invalid", validate.errors); }; module.exports.validateSchema = validateSchema; -/** - * node validation/validate.js - */ -if (require.main === module) { - let json = ""; - let schema = ""; - console.log(process.argv.length); - switch (process.argv.length) { - case 2: - console.log("validating all"); - validateSchema(); - break; - case 3: - json = process.argv[2]; - json = json.replace("/", "\\"); - let n = json.lastIndexOf("\\"); - let jsonKey = json.substring(n + 1); - console.log(json, n); - schema = schemaMap[jsonKey]; - console.log(schema); - validateSchema(json, schema); - break; - case 4: - json = path.resolve(process.argv[2]); - schema = path.resolve(process.argv[3]); - validateSchema(json, schema); - break; - default: - console.log("Error"); +const validateArguments = () => { + try { + let filename = path.basename(argv.files[0]); + let filepath = path.resolve(argv.files[0]); + if (!fs.existsSync(filepath)) { + console.log(filepath); + throw new Error("File does not exist"); + } + let schema = schemaMap[filename]; + if (argv.s) { + schema = path.resolve(argv.s); + } + if (!schema) { + throw new Error("The schema for the file does not exist"); + } + let json = require(filepath); + validateSchema(json, schema); + } catch (e) { + console.log(e.name + ": " + e.message); + return -1; } -} +}; + +validateArguments(); From 7b9faced78dd7c0ce8fefeadcbfe2e3247e27ad1 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Mon, 14 Jun 2021 00:52:27 +0530 Subject: [PATCH 04/11] Working on custom errors --- validation/schemas/quizv2Schema.js | 6 ++- validation/validate.js | 68 +++++++++++++++++++----------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js index dcd762cf..5c858e74 100644 --- a/validation/schemas/quizv2Schema.js +++ b/validation/schemas/quizv2Schema.js @@ -1,7 +1,11 @@ module.exports = { type: "object", properties: { - version: { type: "integer" }, + version: { + type: "integer", + enum: [2], + errorMessage: "Version should be 2.0", + }, questions: { type: "array", items: { diff --git a/validation/validate.js b/validation/validate.js index 2691ff45..b71562b1 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -1,9 +1,12 @@ const Ajv = require("ajv"); +// const AjvErrors = require("ajv-errors"); + const path = require("path"); const fs = require("fs"); const schemaMap = require("./schema-map.json"); const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true} +// AjvErrors(ajv); const argv = require("yargs")(process.argv.slice(2)) .scriptName("validate") @@ -11,23 +14,32 @@ const argv = require("yargs")(process.argv.slice(2)) .option("files", { type: "array", desc: "One or more files for validation", - demandOption: true, + }) + .option("schema-map", { + type: "string", + desc: "The schema map file", + }) + .option("all", { + type: "boolean", + desc: "Verify all jsons", }) .check((argv) => { - if (argv.files.length === 0) { + console.log(argv); + if (!argv.files && !argv.all) { + throw new Error("Required either -f or -a. Run --help for more info"); + } + if (!argv.all && argv.files.length === 0) { throw new Error("Empty Argument: Filenames cannot be empty"); } return true; }) - .option("schema-map", { - type: "string", - desc: "The schema map file", - }) + .alias({ help: "h", version: "v", files: "f", "schema-map": "s", + all: "a", }).argv; let validateSchema = (input = "1", schema = "1") => { @@ -42,26 +54,32 @@ let validateSchema = (input = "1", schema = "1") => { module.exports.validateSchema = validateSchema; const validateArguments = () => { - try { - let filename = path.basename(argv.files[0]); - let filepath = path.resolve(argv.files[0]); - if (!fs.existsSync(filepath)) { - console.log(filepath); - throw new Error("File does not exist"); - } - let schema = schemaMap[filename]; - if (argv.s) { - schema = path.resolve(argv.s); - } - if (!schema) { - throw new Error("The schema for the file does not exist"); + for (let i in argv.files) { + try { + let filename = path.basename(argv.files[i]); + let filepath = path.resolve(argv.files[i]); + if (!fs.existsSync(filepath)) { + console.log(filepath); + throw new Error("File does not exist"); + } + let schema = schemaMap[filename]; + if (argv.s) { + schema = path.resolve(argv.s); + } + if (!schema) { + throw new Error("The schema for the file does not exist"); + } + let json = require(filepath); + validateSchema(json, schema); + } catch (e) { + console.log(e.name + ": " + e.message); + return -1; } - let json = require(filepath); - validateSchema(json, schema); - } catch (e) { - console.log(e.name + ": " + e.message); - return -1; } }; -validateArguments(); +if (argv.all) { + console.log("Validating all jsons\nChecking for available jsons"); +} else { + validateArguments(); +} From d4440116848acefd20624683b13a338f36cfd720 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Mon, 14 Jun 2021 01:06:52 +0530 Subject: [PATCH 05/11] Add support for custom error validation --- package-lock.json | 100 ++++++++++++++++++++++++++++++++++------- package.json | 3 +- validation/validate.js | 17 ++++--- 3 files changed, 96 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index d3475399..e4585dfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "@types/shelljs": "^0.8.8", - "ajv": "^6.12.6", + "ajv": "^8.6.0", + "ajv-errors": "^3.0.0", "boxen": "^4.2.0", "chalk": "^4.1.0", "figures": "^3.2.0", @@ -562,13 +563,13 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -576,6 +577,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, "node_modules/ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -2100,6 +2109,26 @@ "node": ">=6" } }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2539,9 +2568,9 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -3261,6 +3290,14 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -4698,16 +4735,22 @@ } }, "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "requires": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, + "ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "requires": {} + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -5930,6 +5973,24 @@ "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } } }, "has-flag": { @@ -6289,9 +6350,9 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "json-stringify-safe": { "version": "5.0.1", @@ -6867,6 +6928,11 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", diff --git a/package.json b/package.json index 4f162cc0..19fcfe6b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "dependencies": { "@types/shelljs": "^0.8.8", - "ajv": "^6.12.6", + "ajv": "^8.6.0", + "ajv-errors": "^3.0.0", "boxen": "^4.2.0", "chalk": "^4.1.0", "figures": "^3.2.0", diff --git a/validation/validate.js b/validation/validate.js index b71562b1..3089d955 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -1,12 +1,12 @@ const Ajv = require("ajv"); -// const AjvErrors = require("ajv-errors"); +const AjvErrors = require("ajv-errors"); const path = require("path"); const fs = require("fs"); const schemaMap = require("./schema-map.json"); -const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true} -// AjvErrors(ajv); +const ajv = new Ajv({ allErrors: true }); // options can be passed, e.g. {allErrors: true} +AjvErrors(ajv); const argv = require("yargs")(process.argv.slice(2)) .scriptName("validate") @@ -46,9 +46,13 @@ let validateSchema = (input = "1", schema = "1") => { let validationSchema = require(schema); let validate = ajv.compile(validationSchema); let valid = validate(input); - valid - ? console.log("Validated", valid) - : console.log("Invalid", validate.errors); + if (!valid) { + validate.errors.forEach((e) => + console.log(e.instancePath + ": " + e.message) + ); + throw new Error("Schema is Invalid"); + } + console.log("Validated", valid); }; module.exports.validateSchema = validateSchema; @@ -72,6 +76,7 @@ const validateArguments = () => { let json = require(filepath); validateSchema(json, schema); } catch (e) { + console.log("Failed while validating " + argv.files[i]); console.log(e.name + ": " + e.message); return -1; } From 78f2b2fce60b824a0dc0134fc5f480b13c05a0c9 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Mon, 14 Jun 2021 02:02:17 +0530 Subject: [PATCH 06/11] Add more custom error messages --- validation/schemas/quizv2Schema.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js index 5c858e74..10235466 100644 --- a/validation/schemas/quizv2Schema.js +++ b/validation/schemas/quizv2Schema.js @@ -16,12 +16,21 @@ module.exports = { }, answers: { type: "object", + minItems: 1, + errorMessage: { + minItems: "There have to be atleast one correct answer", + }, }, correctAnswer: { type: "string", }, difficulty: { type: "string", + enum: ["beginner", "intermediate", "advanced"], + errorMessage: { + enum: + "Difficulty can only be: beginner, intermediate or advanced", + }, }, explanations: { type: "object", @@ -30,6 +39,11 @@ module.exports = { additionalProperties: false, required: ["question", "answers", "correctAnswer", "difficulty"], }, + minItems: 1, + errorMessage: { + minItems: "Questions cannot be empty", + type: "Please provide an array of questions", + }, }, }, required: ["version", "questions"], From 1cdf3f18f95321d98bf61fe5b46e1c8d9f7e65cb Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 15 Jun 2021 00:55:08 +0530 Subject: [PATCH 07/11] Working implementations of v1 and v2 schema --- validation/schemas/quizv2Schema.js | 87 +++++++++++++++++++----------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js index 10235466..f1f12938 100644 --- a/validation/schemas/quizv2Schema.js +++ b/validation/schemas/quizv2Schema.js @@ -1,12 +1,57 @@ module.exports = { - type: "object", - properties: { - version: { - type: "integer", - enum: [2], - errorMessage: "Version should be 2.0", + oneOf: [ + { + type: "object", + properties: { + version: { + type: "integer", + enum: [2], + errorMessage: "Version should be 2.0", + }, + questions: { + type: "array", + items: { + type: "object", + properties: { + question: { + type: "string", + }, + answers: { + type: "object", + minProperties: 1, + errorMessage: { + minProperties: "There have to be atleast one correct answer", + }, + }, + correctAnswer: { + type: "string", + }, + difficulty: { + type: "string", + enum: ["beginner", "intermediate", "advanced"], + errorMessage: { + enum: + "Difficulty can only be: beginner, intermediate or advanced", + }, + }, + explanations: { + type: "object", + }, + }, + additionalProperties: false, + required: ["question", "answers", "correctAnswer", "difficulty"], + }, + minItems: 1, + errorMessage: { + minItems: "Questions cannot be empty", + type: "Please provide an array of questions", + }, + }, + }, + required: ["version", "questions"], + additionalProperties: false, }, - questions: { + { type: "array", items: { type: "object", @@ -16,36 +61,18 @@ module.exports = { }, answers: { type: "object", - minItems: 1, + minProperties: 1, errorMessage: { - minItems: "There have to be atleast one correct answer", + minProperties: "There have to be atleast one correct answer", }, }, correctAnswer: { type: "string", }, - difficulty: { - type: "string", - enum: ["beginner", "intermediate", "advanced"], - errorMessage: { - enum: - "Difficulty can only be: beginner, intermediate or advanced", - }, - }, - explanations: { - type: "object", - }, }, - additionalProperties: false, - required: ["question", "answers", "correctAnswer", "difficulty"], - }, - minItems: 1, - errorMessage: { - minItems: "Questions cannot be empty", - type: "Please provide an array of questions", + required: ["question", "answers", "correctAnswer"], }, }, - }, - required: ["version", "questions"], - additionalProperties: false, + ], + errorMessage: { anyOf: "The json does not validate with version 1 or 2" }, }; From 267bfa338c0ce5e9229e5c8fb17a1e606970b475 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 15 Jun 2021 01:03:53 +0530 Subject: [PATCH 08/11] Conditional implementation --- validation/schemas/quizv2Schema.js | 132 +++++++++++++++-------------- validation/validate.js | 6 +- 2 files changed, 70 insertions(+), 68 deletions(-) diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js index f1f12938..f9af4b1f 100644 --- a/validation/schemas/quizv2Schema.js +++ b/validation/schemas/quizv2Schema.js @@ -1,78 +1,80 @@ module.exports = { - oneOf: [ - { - type: "object", - properties: { - version: { - type: "integer", - enum: [2], - errorMessage: "Version should be 2.0", - }, - questions: { - type: "array", - items: { - type: "object", - properties: { - question: { - type: "string", - }, - answers: { - type: "object", - minProperties: 1, - errorMessage: { - minProperties: "There have to be atleast one correct answer", - }, - }, - correctAnswer: { - type: "string", - }, - difficulty: { - type: "string", - enum: ["beginner", "intermediate", "advanced"], - errorMessage: { - enum: - "Difficulty can only be: beginner, intermediate or advanced", - }, + type: ["object", "array"], + if: { + type: "object", + }, + then: { + properties: { + version: { + type: "integer", + enum: [2], + errorMessage: "Version should be 2.0", + }, + questions: { + type: "array", + items: { + type: "object", + properties: { + question: { + type: "string", + }, + answers: { + type: "object", + minProperties: 1, + errorMessage: { + minProperties: "There have to be atleast one correct answer", }, - explanations: { - type: "object", + }, + correctAnswer: { + type: "string", + }, + difficulty: { + type: "string", + enum: ["beginner", "intermediate", "advanced"], + errorMessage: { + enum: + "Difficulty can only be: beginner, intermediate or advanced", }, }, - additionalProperties: false, - required: ["question", "answers", "correctAnswer", "difficulty"], - }, - minItems: 1, - errorMessage: { - minItems: "Questions cannot be empty", - type: "Please provide an array of questions", + explanations: { + type: "object", + }, }, + additionalProperties: false, + required: ["question", "answers", "correctAnswer", "difficulty"], + }, + minItems: 1, + errorMessage: { + minItems: "Questions cannot be empty", + type: "Please provide an array of questions", }, }, - required: ["version", "questions"], - additionalProperties: false, }, - { - type: "array", - items: { - type: "object", - properties: { - question: { - type: "string", - }, - answers: { - type: "object", - minProperties: 1, - errorMessage: { - minProperties: "There have to be atleast one correct answer", - }, - }, - correctAnswer: { - type: "string", + required: ["version", "questions"], + additionalProperties: false, + }, + if: { + type: "array", + }, + then: { + items: { + type: "object", + properties: { + question: { + type: "string", + }, + answers: { + type: "object", + minProperties: 1, + errorMessage: { + minProperties: "There have to be atleast one correct answer", }, }, - required: ["question", "answers", "correctAnswer"], + correctAnswer: { + type: "string", + }, }, + required: ["question", "answers", "correctAnswer"], }, - ], - errorMessage: { anyOf: "The json does not validate with version 1 or 2" }, + }, }; diff --git a/validation/validate.js b/validation/validate.js index 3089d955..89200498 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -47,9 +47,9 @@ let validateSchema = (input = "1", schema = "1") => { let validate = ajv.compile(validationSchema); let valid = validate(input); if (!valid) { - validate.errors.forEach((e) => - console.log(e.instancePath + ": " + e.message) - ); + validate.errors.forEach((e) => { + if (e.instancePath) console.log(e.instancePath + ": " + e.message + "\n"); + }); throw new Error("Schema is Invalid"); } console.log("Validated", valid); From 99cca6e882ef8b4b03a49addcdbff330b0d89293 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 22 Jun 2021 12:56:52 +0530 Subject: [PATCH 09/11] Major update * Support for conditional version * Reference schema from external files --- validation/schema-map.json | 6 +-- validation/schemas/quizSchema.js | 24 +++++++++ validation/schemas/quizv2Schema.js | 80 ------------------------------ validation/schemas/qv1.json | 24 +++++++++ validation/schemas/qv2.json | 45 +++++++++++++++++ validation/validate.js | 31 ++++++++++-- 6 files changed, 123 insertions(+), 87 deletions(-) create mode 100644 validation/schemas/quizSchema.js delete mode 100644 validation/schemas/quizv2Schema.js create mode 100644 validation/schemas/qv1.json create mode 100644 validation/schemas/qv2.json diff --git a/validation/schema-map.json b/validation/schema-map.json index aca70695..df174b7c 100644 --- a/validation/schema-map.json +++ b/validation/schema-map.json @@ -1,4 +1,4 @@ { - "posttest.json": "./schemas/quizv2Schema.js", - "pretest.json" : "./schemas/quizv2Schema.js" -} \ No newline at end of file + "posttest.json": "./schemas/quizSchema.js", + "pretest.json": "./schemas/quizSchema.js" +} diff --git a/validation/schemas/quizSchema.js b/validation/schemas/quizSchema.js new file mode 100644 index 00000000..fe3b8216 --- /dev/null +++ b/validation/schemas/quizSchema.js @@ -0,0 +1,24 @@ +module.exports = { + $schema: "http://json-schema.org/draft-07/schema#", + $id: "https://virtual.labs/schemas/quizSchema.json", + type: ["object", "array"], + if: { type: "array" }, + then: { + items: { $ref: "qv1.json#/items" }, + }, + if: { type: "object" }, + then: { + properties: { + version: { + type: "integer", + enum: [2], + errorMessage: "Version should be 2.0", + }, + }, + if: { properties: { version: { const: 2 } }, required: ["version"] }, + then: { + required: ["questions"], + properties: { questions: { $ref: "qv2.json#/properties/questions" } }, + }, + }, +}; diff --git a/validation/schemas/quizv2Schema.js b/validation/schemas/quizv2Schema.js deleted file mode 100644 index f9af4b1f..00000000 --- a/validation/schemas/quizv2Schema.js +++ /dev/null @@ -1,80 +0,0 @@ -module.exports = { - type: ["object", "array"], - if: { - type: "object", - }, - then: { - properties: { - version: { - type: "integer", - enum: [2], - errorMessage: "Version should be 2.0", - }, - questions: { - type: "array", - items: { - type: "object", - properties: { - question: { - type: "string", - }, - answers: { - type: "object", - minProperties: 1, - errorMessage: { - minProperties: "There have to be atleast one correct answer", - }, - }, - correctAnswer: { - type: "string", - }, - difficulty: { - type: "string", - enum: ["beginner", "intermediate", "advanced"], - errorMessage: { - enum: - "Difficulty can only be: beginner, intermediate or advanced", - }, - }, - explanations: { - type: "object", - }, - }, - additionalProperties: false, - required: ["question", "answers", "correctAnswer", "difficulty"], - }, - minItems: 1, - errorMessage: { - minItems: "Questions cannot be empty", - type: "Please provide an array of questions", - }, - }, - }, - required: ["version", "questions"], - additionalProperties: false, - }, - if: { - type: "array", - }, - then: { - items: { - type: "object", - properties: { - question: { - type: "string", - }, - answers: { - type: "object", - minProperties: 1, - errorMessage: { - minProperties: "There have to be atleast one correct answer", - }, - }, - correctAnswer: { - type: "string", - }, - }, - required: ["question", "answers", "correctAnswer"], - }, - }, -}; diff --git a/validation/schemas/qv1.json b/validation/schemas/qv1.json new file mode 100644 index 00000000..de57d6df --- /dev/null +++ b/validation/schemas/qv1.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://virtual.labs/schemas/qv1.json", + "type": "array", + "items": { + "type": "object", + "properties": { + "question": { + "type": "string" + }, + "answers": { + "type": "object", + "minProperties": 1, + "errorMessage": { + "minProperties": "There have to be atleast one correct answer" + } + }, + "correctAnswer": { + "type": "string" + } + }, + "required": ["question", "answers", "correctAnswer"] + } +} diff --git a/validation/schemas/qv2.json b/validation/schemas/qv2.json new file mode 100644 index 00000000..749e63ad --- /dev/null +++ b/validation/schemas/qv2.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://virtual.labs/schemas/qv2.json", + "type": "object", + "properties": { + "questions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "question": { + "type": "string" + }, + "answers": { + "type": "object", + "minProperties": 1, + "errorMessage": { + "minProperties": "There have to be atleast one correct answer" + } + }, + "correctAnswer": { + "type": "string" + }, + "difficulty": { + "type": "string", + "enum": ["beginner", "intermediate", "advanced"], + "errorMessage": { + "enum": "Difficulty can only be: beginner, intermediate or advanced" + } + }, + "explanations": { + "type": "object" + } + }, + "additionalProperties": false, + "required": ["question", "answers", "correctAnswer", "difficulty"] + }, + "minItems": 1, + "errorMessage": { + "minItems": "Questions cannot be empty", + "type": "Please provide an array of questions" + } + } + } +} diff --git a/validation/validate.js b/validation/validate.js index 89200498..8f87d761 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -4,8 +4,14 @@ const AjvErrors = require("ajv-errors"); const path = require("path"); const fs = require("fs"); const schemaMap = require("./schema-map.json"); +const qv1Schema = require("./schemas/qv1.json"); +const qv2Schema = require("./schemas/qv2.json"); -const ajv = new Ajv({ allErrors: true }); // options can be passed, e.g. {allErrors: true} +const ajv = new Ajv({ + allErrors: true, + allowUnionTypes: true, + schemas: [qv1Schema, qv2Schema], +}); // options can be passed, e.g. {allErrors: true} AjvErrors(ajv); const argv = require("yargs")(process.argv.slice(2)) @@ -23,6 +29,11 @@ const argv = require("yargs")(process.argv.slice(2)) type: "boolean", desc: "Verify all jsons", }) + .option("debug", { + type: "boolean", + desc: "Debug erros", + }) + .check((argv) => { console.log(argv); if (!argv.files && !argv.all) { @@ -40,6 +51,7 @@ const argv = require("yargs")(process.argv.slice(2)) files: "f", "schema-map": "s", all: "a", + debug: "d", }).argv; let validateSchema = (input = "1", schema = "1") => { @@ -47,9 +59,17 @@ let validateSchema = (input = "1", schema = "1") => { let validate = ajv.compile(validationSchema); let valid = validate(input); if (!valid) { - validate.errors.forEach((e) => { - if (e.instancePath) console.log(e.instancePath + ": " + e.message + "\n"); - }); + if (argv.debug) { + console.log(validate.errors); + } else { + validate.errors.forEach((e) => { + if (e.instancePath) { + console.log(e.instancePath + ": " + e.message + "\n"); + } else { + console.log("Json Error: " + e.message); + } + }); + } throw new Error("Schema is Invalid"); } console.log("Validated", valid); @@ -78,6 +98,9 @@ const validateArguments = () => { } catch (e) { console.log("Failed while validating " + argv.files[i]); console.log(e.name + ": " + e.message); + if (argv.debug) { + console.log(e); + } return -1; } } From 525ddfec151c28807198da82f5d5d422163b08e2 Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 6 Jul 2021 13:53:14 +0530 Subject: [PATCH 10/11] Make schema inclusion generic * Show that the versioning supports major.minor --- validation/schemas/quizSchema.js | 4 ++-- validation/validate.js | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/validation/schemas/quizSchema.js b/validation/schemas/quizSchema.js index fe3b8216..bdf9801a 100644 --- a/validation/schemas/quizSchema.js +++ b/validation/schemas/quizSchema.js @@ -11,11 +11,11 @@ module.exports = { properties: { version: { type: "integer", - enum: [2], + enum: [2.0], errorMessage: "Version should be 2.0", }, }, - if: { properties: { version: { const: 2 } }, required: ["version"] }, + if: { properties: { version: { const: 2.0 } }, required: ["version"] }, then: { required: ["questions"], properties: { questions: { $ref: "qv2.json#/properties/questions" } }, diff --git a/validation/validate.js b/validation/validate.js index 8f87d761..bfc77da2 100644 --- a/validation/validate.js +++ b/validation/validate.js @@ -4,13 +4,16 @@ const AjvErrors = require("ajv-errors"); const path = require("path"); const fs = require("fs"); const schemaMap = require("./schema-map.json"); -const qv1Schema = require("./schemas/qv1.json"); -const qv2Schema = require("./schemas/qv2.json"); +const schemaPaths = ["./schemas/qv1.json", "./schemas/qv2.json"]; +let schemas = []; +schemaPaths.forEach((path) => { + schemas[schemas.length] = require(path); +}); const ajv = new Ajv({ allErrors: true, allowUnionTypes: true, - schemas: [qv1Schema, qv2Schema], + schemas: schemas, }); // options can be passed, e.g. {allErrors: true} AjvErrors(ajv); From a383ab002c67dda27bfc5517df2ca7d59c7c98ed Mon Sep 17 00:00:00 2001 From: vjspranav Date: Tue, 6 Jul 2021 13:55:13 +0530 Subject: [PATCH 11/11] Make sure there is at least one question and at least two answers --- validation/schemas/qv1.json | 5 +++-- validation/schemas/qv2.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/validation/schemas/qv1.json b/validation/schemas/qv1.json index de57d6df..f40f06ee 100644 --- a/validation/schemas/qv1.json +++ b/validation/schemas/qv1.json @@ -10,7 +10,7 @@ }, "answers": { "type": "object", - "minProperties": 1, + "minProperties": 2, "errorMessage": { "minProperties": "There have to be atleast one correct answer" } @@ -20,5 +20,6 @@ } }, "required": ["question", "answers", "correctAnswer"] - } + }, + "minItems": 1 } diff --git a/validation/schemas/qv2.json b/validation/schemas/qv2.json index 749e63ad..bc9701e2 100644 --- a/validation/schemas/qv2.json +++ b/validation/schemas/qv2.json @@ -13,7 +13,7 @@ }, "answers": { "type": "object", - "minProperties": 1, + "minProperties": 2, "errorMessage": { "minProperties": "There have to be atleast one correct answer" }