detailed-xml-validator
Advanced tools
| const { assert, expect } = require('chai'); | ||
| const Validator = require("../src/validator"); | ||
| describe("XML validator with checkBy", function() { | ||
| it("custom validator should be called", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>0</a> | ||
| <c>3.2</c> | ||
| <d>3.2</d> | ||
| <f> | ||
| <a>1</a> | ||
| <b>1</b> | ||
| </f> | ||
| <f> | ||
| <a>2</a> | ||
| <b>3</b> | ||
| </f> | ||
| <f> | ||
| <a>6</a> | ||
| </f> | ||
| <f> | ||
| <a>4</a> | ||
| <b>5</b> | ||
| <c>6</c> | ||
| </f> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="positiveInteger" min="3"></a> | ||
| <c type="decimal" min="1.2"></c> | ||
| <d type="number" min="1.2" max="1.5"></d> | ||
| <f repeatable checkBy="fValidator"></f> | ||
| </root>`; | ||
| let calls = []; | ||
| const validator = new Validator(rules); | ||
| validator.register("fValidator", (f,path) => { | ||
| calls.push("fValidator"); | ||
| if(f.a==1 && f.b== 1) return; | ||
| else if(f.a==2 && f.b== 3) return; | ||
| else if(f.a==4 && f.b== 5 && f.c != undefined) return; | ||
| return { | ||
| code: "I dont know", | ||
| path: path, | ||
| } | ||
| }) | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'min', path: 'root.a', actual: 0, expected: 3 }, | ||
| { code: 'max', path: 'root.d', actual: 3.2, expected: 1.5 }, | ||
| { code: 'I dont know', path: 'root.f[2]' } | ||
| ]); | ||
| expect(calls.length).to.eq(4); | ||
| }); | ||
| it("custom validator should not stop validations on nested element", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <f> | ||
| <a>1</a> | ||
| <b>1</b> | ||
| </f> | ||
| <f> | ||
| <a>2</a> | ||
| <b>3</b> | ||
| </f> | ||
| <f> | ||
| <a>6</a> | ||
| </f> | ||
| <f> | ||
| <a>4</a> | ||
| <b>5</b> | ||
| <c>6</c> | ||
| </f> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <f repeatable checkBy="fValidator"> | ||
| <a pattern="1|2|4"/> | ||
| </f> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| validator.register("fValidator", (f,path) => { | ||
| if(f.a==1 && f.b== 1) return; | ||
| else if(f.a==2 && f.b== 3) return; | ||
| else if(f.a==4 && f.b== 5 && f.c != undefined) return; | ||
| return { | ||
| code: "I dont know", | ||
| path: path, | ||
| } | ||
| }) | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'I dont know', path: 'root.f[2]' }, | ||
| { | ||
| code: 'pattern', | ||
| path: 'root.f[2].a', | ||
| actual: '6', | ||
| expected: '1|2|4' | ||
| } | ||
| ]); | ||
| }); | ||
| it("custom validator should be called for leaf tag", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <f>value</f> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <f checkBy="fValidator"></f> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| validator.register("fValidator", (f,path) => { | ||
| return { | ||
| code: "I dont know", | ||
| path: path, | ||
| } | ||
| }) | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'I dont know', path: 'root.f' } | ||
| ]); | ||
| }); | ||
| }); |
| const { assert, expect } = require('chai'); | ||
| const Validator = require("../src/validator"); | ||
| const fs = require("fs"); | ||
| const path = require("path"); | ||
| describe("XML validator with Number", function() { | ||
| //type:string | ||
| it("when string length cross the boundary", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>amit</a> | ||
| <b>kumar</b> | ||
| <c>gupta</c> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="string" minLength="3"></a> | ||
| <b length="4"></b> | ||
| <c minLength="2" maxLength="5" ></c> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'length', path: 'root.b', actual: 'kumar', expected: 4 } | ||
| ]); | ||
| }); | ||
| it("when pattern doesn't match", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>0</a> | ||
| <a>amitguptagmail.com</a> | ||
| <a>amit@gmail.com</a> | ||
| <a>amitgupta@gmail.com</a> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a repeatable pattern="[a-z]+@gmail.com" minLength="15"></a> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'minLength', path: 'root.a[0]', actual: '0', expected: 15 }, | ||
| { | ||
| code: 'pattern', | ||
| path: 'root.a[0]', | ||
| actual: '0', | ||
| expected: '[a-z]+@gmail.com' | ||
| }, | ||
| { | ||
| code: 'pattern', | ||
| path: 'root.a[1]', | ||
| actual: 'amitguptagmail.com', | ||
| expected: '[a-z]+@gmail.com' | ||
| }, | ||
| { | ||
| code: 'minLength', | ||
| path: 'root.a[2]', | ||
| actual: 'amit@gmail.com', | ||
| expected: 15 | ||
| } | ||
| ]); | ||
| }); | ||
| it("when pattern doesn't match with modifier", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>0</a> | ||
| <a>amitguptagmail.com</a> | ||
| <a>amit@gmail.com</a> | ||
| <a>amitgupta@gmail.com</a> | ||
| <a>AmitGupta@Gmail.com</a> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a repeatable pattern_i="[a-z]+@gmail.com" minLength="15"></a> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'minLength', path: 'root.a[0]', actual: '0', expected: 15 }, | ||
| { | ||
| code: 'pattern', | ||
| path: 'root.a[0]', | ||
| actual: '0', | ||
| expected: '[a-z]+@gmail.com' | ||
| }, | ||
| { | ||
| code: 'pattern', | ||
| path: 'root.a[1]', | ||
| actual: 'amitguptagmail.com', | ||
| expected: '[a-z]+@gmail.com' | ||
| }, | ||
| { | ||
| code: 'minLength', | ||
| path: 'root.a[2]', | ||
| actual: 'amit@gmail.com', | ||
| expected: 15 | ||
| } | ||
| ]); | ||
| }); | ||
| it("when a fixed string is given", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>amit</a> | ||
| <b>kumar</b> | ||
| <c>gupta</c> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="string" minLength="3" fixed="amit"></a> | ||
| <b length="4" fixed="-"></b> | ||
| <c minLength="2" maxLength="5" ></c> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'length', path: 'root.b', actual: 'kumar', expected: 4 }, | ||
| { code: 'fixed', path: 'root.b', actual: 'kumar', expected: '-' } | ||
| ]); | ||
| }); | ||
| it("when a list of strings are given for repeatable tags", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>amit</a> | ||
| <b>kumar</b> | ||
| <b>-</b> | ||
| <b>middle</b> | ||
| <c>gupta</c> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="string" minLength="3" fixed="amit"></a> | ||
| <b repeatable in="-,kumar"></b> | ||
| <c minLength="2" maxLength="5" ></c> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'in', path: 'root.b[2]', actual: 'middle', expected: '-,kumar' } | ||
| ]); | ||
| }); | ||
| it("when a list of strings are given for leaf tag", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>amit</a> | ||
| <b>middle</b> | ||
| <c>gupta</c> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="string" minLength="3" fixed="amit"></a> | ||
| <b in="-,kumar"></b> | ||
| <c minLength="2" maxLength="5" ></c> | ||
| </root>`; | ||
| const validator = new Validator(rules); | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'in', path: 'root.b', actual: 'middle', expected: '-,kumar' } | ||
| ]); | ||
| }); | ||
| }); |
| const { assert, expect } = require('chai'); | ||
| const Validator = require("../src/validator"); | ||
| describe("XML validator with checkBy", function() { | ||
| it("custom validator should be called", function(){ | ||
| const xmlData = ` | ||
| <root> | ||
| <a>0</a> | ||
| <c>3.2</c> | ||
| <d>3.2</d> | ||
| <f> | ||
| <a>1</a> | ||
| <b>1</b> | ||
| </f> | ||
| <f> | ||
| <a>2</a> | ||
| <b>3</b> | ||
| </f> | ||
| <f> | ||
| <a>6</a> | ||
| </f> | ||
| <f> | ||
| <a>4</a> | ||
| <b>5</b> | ||
| <c>6</c> | ||
| </f> | ||
| </root>`; | ||
| const rules = ` | ||
| <root> | ||
| <a type="positiveInteger" min="3"></a> | ||
| <c type="decimal" min="1.2"></c> | ||
| <d type="number" min="1.2" max="1.5"></d> | ||
| <f repeatable checkBy="fValidator"></f> | ||
| </root>`; | ||
| let calls = []; | ||
| const validator = new Validator(rules); | ||
| validator.register("fValidator", (f,path) => { | ||
| calls.push("fValidator"); | ||
| if(f.a==1 && f.b== 1) return; | ||
| else if(f.a==2 && f.b== 3) return; | ||
| else if(f.a==4 && f.b== 5 && f.c != undefined) return; | ||
| return { | ||
| code: "I dont know", | ||
| path: path, | ||
| } | ||
| }) | ||
| const actual = validator.validate(xmlData); | ||
| // console.log(actual); | ||
| expect(actual).to.deep.equal([ | ||
| { code: 'min', path: 'root.a', actual: 0, expected: 3 }, | ||
| { code: 'max', path: 'root.d', actual: 3.2, expected: 1.5 }, | ||
| { code: 'I dont know', path: 'root.f[2]' } | ||
| ]); | ||
| expect(calls.length).to.eq(4); | ||
| }); | ||
| }); |
+1
-1
| { | ||
| "name": "detailed-xml-validator", | ||
| "version": "0.0.7", | ||
| "version": "1.0.0", | ||
| "description": "Validate for XML schema and returns all the possible failures", | ||
@@ -5,0 +5,0 @@ "main": "./src/validator.js", |
+13
-2
@@ -27,7 +27,9 @@ # detailed-xml-validator | ||
| <marks> | ||
| <subject repeatable minOccurs="5" maxOccurs="6" > | ||
| <subject repeatable minOccurs="5" maxOccurs="6" checkBy="subjectValidator"> | ||
| <name pattern="math|hindi|english|science|history"></name> | ||
| <!-- <name in="math,hindi,english,science,history"></name> --> | ||
| <score type="positiveDecimal"></score> | ||
| </subject> | ||
| </marks> | ||
| </student> | ||
@@ -58,7 +60,11 @@ </students> | ||
| * **length**: | ||
| * **pattern**: regex | ||
| * **in**: comma separated string for exact match (from v1.0.0) | ||
| * **fixed**: exact match (from v1.0.0) | ||
| * **pattern**: regex match | ||
| * **pattern_i**: regex (case insensitive) | ||
| * **pattern_m**: regex (multiline) | ||
| * **pattern_im**: regex (case insencitive and multiline) | ||
| * **checkBy**: (from v1.0.0) Give the name of validator that you registered with validator. This validator will be called with an object of nested tags (or value if it is a leaf node) and path. | ||
| Sample code | ||
@@ -74,2 +80,7 @@ ```js | ||
| const validator = new Validator(rules, options); | ||
| validator.register("subjectValidator", (obj, path) => { //From v1.0.0 | ||
| //return; //if no error | ||
| //return {} //return an error msg object | ||
| }) | ||
| const failures = validator.validate(xmlStringData); | ||
@@ -76,0 +87,0 @@ const originalXmlJsObj = validator.data; |
+21
-1
@@ -9,5 +9,6 @@ /// @ts-check | ||
| class Traverser{ | ||
| constructor(options){ | ||
| constructor(options, validators){ | ||
| this.options = options; | ||
| this.failures = []; | ||
| this.validators=validators; | ||
| } | ||
@@ -50,5 +51,15 @@ | ||
| } | ||
| this.applyCustomValidators(ele, rules, path); | ||
| } | ||
| } | ||
| applyCustomValidators(ele, rules, path){ | ||
| if(rules['@rules'] && rules['@rules'].checkBy && typeof this.validators[rules['@rules'].checkBy] === "function"){ | ||
| let res = this.validators[rules['@rules'].checkBy](ele, path.substr(1)); | ||
| if(typeof res === "object"){ | ||
| this.failures.push(res); | ||
| } | ||
| } | ||
| } | ||
| callForCommonProperties(ele, rules, path){ | ||
@@ -62,2 +73,3 @@ const tags = Object.keys(ele); | ||
| this.applyCustomValidators(ele, rules, path); | ||
| sets.common.forEach(key => { | ||
@@ -203,2 +215,10 @@ const newpath = path + "." + key; | ||
| }); | ||
| ["fixed","in"].forEach( rule => { | ||
| if(rules[rule] !== undefined){ | ||
| const expected = rules[rule]; | ||
| if( !validations.string[rule](expected, actual) ){ | ||
| this.setInvalidValueError(rule, newpath, actual, expected); | ||
| }; | ||
| } | ||
| }); | ||
| // if(rules.pattern){ | ||
@@ -205,0 +225,0 @@ // const expected = rules[rule]; |
@@ -14,2 +14,8 @@ module.exports.string = { | ||
| return regxp.test(actual); | ||
| }, | ||
| fixed: function(expected, actual){ | ||
| return expected === actual; | ||
| }, | ||
| in: function(expected, actual){ | ||
| return expected.split(",").indexOf(actual) > -1 | ||
| } | ||
@@ -26,3 +32,2 @@ } | ||
| module.exports.list = { | ||
| minOccurs: function(expected, actual){ | ||
@@ -29,0 +34,0 @@ return actual >= expected; |
+5
-1
@@ -20,4 +20,8 @@ /// @ts-check | ||
| this.options = Object.assign({}, defaultOptions, options); | ||
| this.validators={}; | ||
| } | ||
| register(validator, fn){ | ||
| this.validators[validator] = fn; | ||
| } | ||
| validate(xmldata){ | ||
@@ -32,3 +36,3 @@ validateXMlData(xmldata); | ||
| this.data = xmlObj; | ||
| const traverser = new Traverser(this.options); | ||
| const traverser = new Traverser(this.options,this.validators); | ||
| traverser.traverse (xmlObj, "", this.rules, ""); | ||
@@ -35,0 +39,0 @@ return traverser.failures; |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
63017
25.08%25
13.64%1574
30.84%1
-50%106
11.58%8
14.29%