Skip to content

Commit

Permalink
Add validator support for required_by_default and no_additional_prope…
Browse files Browse the repository at this point in the history
…rties.

Need to add oneOf expansion to expandSchema in the validator.
Each oneOf should inherit all the properties of the parent.  This will make validation easier.
  • Loading branch information
jdorn committed Feb 12, 2014
1 parent 8bdf637 commit 353564b
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 56 deletions.
71 changes: 61 additions & 10 deletions dist/jquery.jsoneditor.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*! JSON Editor v0.4.36 - JSON Schema -> HTML Editor
/*! JSON Editor v0.4.37 - JSON Schema -> HTML Editor
* By Jeremy Dorn - https://github.com/jdorn/json-editor/
* Released under the MIT license
*
* Date: 2014-02-07
* Date: 2014-02-12
*/

/**
Expand Down Expand Up @@ -114,7 +114,9 @@ $.fn.jsoneditor = function(options) {
// Let the validator resolve references in the schema asynchronously
d.validator = new $.jsoneditor.Validator(schema,{
ajax: options.ajax,
refs: options.refs
refs: options.refs,
no_additional_properties: options.no_additional_properties,
required_by_default: options.required_by_default
});
d.validator.ready(function(expanded) {
if(d.ready) return;
Expand Down Expand Up @@ -404,9 +406,20 @@ $.jsoneditor.Validator = Class.extend({
return errors;
}
}
// Value not defined
else if(typeof value === "undefined") {
// Not required and not defined, no further validation needed
return errors;
// If required_by_default is set, all fields are required
if(this.options.required_by_default) {
errors.push({
path: path,
property: 'required',
message: 'Property must be set'
});
}
// Not required, no further validation needed
else {
return errors;
}
}

// `enum`
Expand Down Expand Up @@ -459,10 +472,19 @@ $.jsoneditor.Validator = Class.extend({
// `oneOf`
if(schema.oneOf) {
valid = 0;
var oneof_errors = [];
for(i=0; i<schema.oneOf.length; i++) {
if(!this._validateSchema(schema.oneOf[i],value,path).length) {
// Set the error paths to be path.oneOf[i].rest.of.path
var tmp = this._validateSchema(schema.oneOf[i],value,path);
if(!tmp.length) {
valid++;
}

for(var j=0; j<tmp.length; j++) {
tmp[j].path = path+'.oneOf['+i+']'+tmp[j].path.substr(path.length);
}
oneof_errors = oneof_errors.concat(tmp);

}
if(valid !== 1) {
errors.push({
Expand All @@ -471,6 +493,7 @@ $.jsoneditor.Validator = Class.extend({
message: 'Value must validate against exactly one of the provided schemas. '+
'It currently validates against '+valid+' of the schemas.'
});
errors = errors.concat(oneof_errors);
}
}

Expand Down Expand Up @@ -796,6 +819,11 @@ $.jsoneditor.Validator = Class.extend({
}
}

// The no_additional_properties option currently doesn't work with extended schemas that use oneOf or anyOf
if(typeof schema.additionalProperties === "undefined" && this.options.no_additional_properties && !schema.oneOf && !schema.anyOf) {
schema.additionalProperties = false;
}

// `additionalProperties`
if(typeof schema.additionalProperties !== "undefined") {
for(i in value) {
Expand Down Expand Up @@ -2948,6 +2976,7 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
this.types = [];

if(this.schema.oneOf) {
this.oneOf = true;
this.types = this.schema.oneOf;
delete this.schema.oneOf;
}
Expand Down Expand Up @@ -3029,7 +3058,10 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
}
}

self.validators[i] = new $.jsoneditor.Validator(schema);
self.validators[i] = new $.jsoneditor.Validator(schema,{
required_by_default: self.jsoneditor.data('jsoneditor').options.required_by_default,
no_additional_properties: self.jsoneditor.data('jsoneditor').options.no_additional_properties
});

var editor = $.jsoneditor.getEditorClass(schema, self.jsoneditor);

Expand Down Expand Up @@ -3080,9 +3112,28 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
},
showValidationErrors: function(errors) {
var self = this;
$.each(this.editors,function(type,editor) {
editor.showValidationErrors(errors);
});

// oneOf error paths need to remove the oneOf[i] part before passing to child editors
if(this.oneOf) {
$.each(this.editors,function(i,editor) {
var check = self.path+'.oneOf['+i+']';
var new_errors = [];
$.each(errors, function(j,error) {
if(error.path.substr(0,check.length)===check) {
var new_error = $.extend({},error);
new_error.path = self.path+new_error.path.substr(check.length);
new_errors.push(new_error);
}
});

editor.showValidationErrors(new_errors);
});
}
else {
$.each(this.editors,function(type,editor) {
editor.showValidationErrors(errors);
});
}
}
});

Expand Down
10 changes: 5 additions & 5 deletions dist/jquery.jsoneditor.min.js

Large diffs are not rendered by default.

25 changes: 21 additions & 4 deletions examples/advanced.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ <h1>Advanced JSON Editor Example</h1>
gender: "male",
location: {
city: "San Francisco",
state: "California"
state: "California",
citystate: ""
},
pets: [
{
Expand All @@ -62,14 +63,30 @@ <h1>Advanced JSON Editor Example</h1>
schema: {
type: "array",
title: "People",
format: "tabs",
items: {
// Load the person.json schema via ajax
$ref: "person.json"
title: "Person",
oneOf: [
{
$ref: "basic_person.json",
title: "Basic Person"
},
{
$ref: "person.json",
title: "Complex Person"
}
]
}
},

// Seed the form with a starting value
startval: starting_value
startval: starting_value,

// Disable additional properties
no_additional_properties: true,

// Require all properties by default
required_by_default: true
});

// Hook up the submit button to log to the console
Expand Down
28 changes: 28 additions & 0 deletions examples/basic_person.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"title": "Person",
"type": "object",
"id": "person",
"properties": {
"name": {
"type": "string",
"description": "First and Last name",
"minLength": 4
},
"age": {
"type": "integer",
"default": 21,
"minimum": 18,
"maximum": 99
},
"gender": {
"type": "string",
"enum": [
"male",
"female"
]
}
},
"required": [
"name"
]
}
29 changes: 2 additions & 27 deletions examples/person.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
{
"title": "Person",
"type": "object",
"id": "person",
"$ref": "basic_person.json",
"properties": {
"name": {
"type": "string",
"description": "First and Last name",
"minLength": 4
},
"age": {
"type": "integer",
"default": 21,
"minimum": 18,
"maximum": 99
},
"gender": {
"type": "string",
"enum": [
"male",
"female"
]
},
"location": {
"type": "object",
"title": "Location",
Expand Down Expand Up @@ -81,10 +61,5 @@
]
}
}
},
"required": [
"name",
"age",
"gender"
]
}
}
4 changes: 3 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ $.fn.jsoneditor = function(options) {
// Let the validator resolve references in the schema asynchronously
d.validator = new $.jsoneditor.Validator(schema,{
ajax: options.ajax,
refs: options.refs
refs: options.refs,
no_additional_properties: options.no_additional_properties,
required_by_default: options.required_by_default
});
d.validator.ready(function(expanded) {
if(d.ready) return;
Expand Down
31 changes: 27 additions & 4 deletions src/editors/multiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
this.types = [];

if(this.schema.oneOf) {
this.oneOf = true;
this.types = this.schema.oneOf;
delete this.schema.oneOf;
}
Expand Down Expand Up @@ -91,7 +92,10 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
}
}

self.validators[i] = new $.jsoneditor.Validator(schema);
self.validators[i] = new $.jsoneditor.Validator(schema,{
required_by_default: self.jsoneditor.data('jsoneditor').options.required_by_default,
no_additional_properties: self.jsoneditor.data('jsoneditor').options.no_additional_properties
});

var editor = $.jsoneditor.getEditorClass(schema, self.jsoneditor);

Expand Down Expand Up @@ -142,8 +146,27 @@ $.jsoneditor.editors.multiple = $.jsoneditor.AbstractEditor.extend({
},
showValidationErrors: function(errors) {
var self = this;
$.each(this.editors,function(type,editor) {
editor.showValidationErrors(errors);
});

// oneOf error paths need to remove the oneOf[i] part before passing to child editors
if(this.oneOf) {
$.each(this.editors,function(i,editor) {
var check = self.path+'.oneOf['+i+']';
var new_errors = [];
$.each(errors, function(j,error) {
if(error.path.substr(0,check.length)===check) {
var new_error = $.extend({},error);
new_error.path = self.path+new_error.path.substr(check.length);
new_errors.push(new_error);
}
});

editor.showValidationErrors(new_errors);
});
}
else {
$.each(this.editors,function(type,editor) {
editor.showValidationErrors(errors);
});
}
}
});
4 changes: 2 additions & 2 deletions src/intro.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*! JSON Editor v0.4.36 - JSON Schema -> HTML Editor
/*! JSON Editor v0.4.37 - JSON Schema -> HTML Editor
* By Jeremy Dorn - https://github.com/jdorn/json-editor/
* Released under the MIT license
*
* Date: 2014-02-07
* Date: 2014-02-12
*/

/**
Expand Down
32 changes: 29 additions & 3 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,20 @@ $.jsoneditor.Validator = Class.extend({
return errors;
}
}
// Value not defined
else if(typeof value === "undefined") {
// Not required and not defined, no further validation needed
return errors;
// If required_by_default is set, all fields are required
if(this.options.required_by_default) {
errors.push({
path: path,
property: 'required',
message: 'Property must be set'
});
}
// Not required, no further validation needed
else {
return errors;
}
}

// `enum`
Expand Down Expand Up @@ -256,10 +267,19 @@ $.jsoneditor.Validator = Class.extend({
// `oneOf`
if(schema.oneOf) {
valid = 0;
var oneof_errors = [];
for(i=0; i<schema.oneOf.length; i++) {
if(!this._validateSchema(schema.oneOf[i],value,path).length) {
// Set the error paths to be path.oneOf[i].rest.of.path
var tmp = this._validateSchema(schema.oneOf[i],value,path);
if(!tmp.length) {
valid++;
}

for(var j=0; j<tmp.length; j++) {
tmp[j].path = path+'.oneOf['+i+']'+tmp[j].path.substr(path.length);
}
oneof_errors = oneof_errors.concat(tmp);

}
if(valid !== 1) {
errors.push({
Expand All @@ -268,6 +288,7 @@ $.jsoneditor.Validator = Class.extend({
message: 'Value must validate against exactly one of the provided schemas. '+
'It currently validates against '+valid+' of the schemas.'
});
errors = errors.concat(oneof_errors);
}
}

Expand Down Expand Up @@ -593,6 +614,11 @@ $.jsoneditor.Validator = Class.extend({
}
}

// The no_additional_properties option currently doesn't work with extended schemas that use oneOf or anyOf
if(typeof schema.additionalProperties === "undefined" && this.options.no_additional_properties && !schema.oneOf && !schema.anyOf) {
schema.additionalProperties = false;
}

// `additionalProperties`
if(typeof schema.additionalProperties !== "undefined") {
for(i in value) {
Expand Down

0 comments on commit 353564b

Please sign in to comment.