Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New validation features #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/errorTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,29 @@ StringNotInEnumError.prototype.constructor = StringNotInEnumError;
exports.StringNotInEnumError = StringNotInEnumError;


function StringFormatNotValidError(value, pattern){
this.name = 'StringFormatNotValidError';
this.message = '"' + value + '" is not an acceptable value: "' + pattern + '"';

this.value = value;
}
StringFormatNotValidError.prototype = Object.create(DataTypeValidationError.prototype);
StringFormatNotValidError.prototype.constructor = StringFormatNotValidError;
exports.StringFormatNotValidError = StringFormatNotValidError;


function NotADateValueError(value, actualType){
this.name = 'NotADateValueError';
this.message = '"' + value + '" is not a date value';
if(actualType) this.message += ' (got a ' + actualType + ' instead)';

this.value = value;
}
NotADateValueError.prototype = Object.create(DataTypeValidationError.prototype);
NotADateValueError.prototype.constructor = NotADateValueError;
exports.NotADateValueError = NotADateValueError;


function ErrorsInArrayElementsError(errors){
this.name = 'ErrorsInArrayElementsError';
this.message = 'Errors in array elements:\n\t' + errors.join(',\n\t');
Expand All @@ -129,6 +152,15 @@ MissingValueError.prototype = Object.create(DataTypeValidationError.prototype);
MissingValueError.prototype.constructor = MissingValueError;
exports.MissingValueError = MissingValueError;

function UnexpectedValueError(){
this.name = 'UnexpectedValueError';

this.message = 'This value is unexpected';
}
UnexpectedValueError.prototype = Object.create(DataTypeValidationError.prototype);
UnexpectedValueError.prototype.constructor = UnexpectedValueError;
exports.UnexpectedValueError = UnexpectedValueError;

function ValidationError(specName, spec, error){
this.name = 'ValidationError';
this.specName = specName;
Expand Down
10 changes: 7 additions & 3 deletions src/validateDataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ function validateDataType(candidate, dataType, models){
models = models || {};

var type = dataType.type || dataType.dataType || dataType.$ref;
var format = dataType.format;
var pattern = dataType.pattern;

switch(type){
case 'integer':
return validate.primitive.integer(candidate, dataType);
return validate.primitive.integer(candidate, dataType, format);
case 'number':
return validate.primitive.number(candidate, dataType);
return validate.primitive.number(candidate, dataType, format);
case 'string':
return validate.primitive.string(candidate, dataType);
return validate.primitive.string(candidate, dataType, format, pattern);
case 'boolean':
return validate.primitive.boolean(candidate);
case 'array':
Expand All @@ -22,6 +24,8 @@ function validateDataType(candidate, dataType, models){
return validate.primitive.void(candidate);
case 'File':
return validate.primitive.file();
case 'date-time':
return validate.primitive.dateTime();
default:
// Assumed to be complex model
var model = models[type];
Expand Down
13 changes: 10 additions & 3 deletions src/validateModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var errorTypes = require('./errorTypes'),
ValidationError = errorTypes.ValidationError,
ValidationErrors = errorTypes.ValidationErrors,
MissingValueError = errorTypes.MissingValueError,
UnexpectedValueError = errorTypes.UnexpectedValueError,
validate = require('./index');

// http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object
Expand Down Expand Up @@ -43,12 +44,13 @@ function addInhertiedProperties(model, modelId, models){
addInhertiedProperties(model, parent.id, models);
}

function validateModel(candidate, model, models){
function validateModel(candidate, model, models, options){
if(candidate === null || typeof candidate !== 'object'){
return new ValidationErrors(candidate, model);
}

models = models || {};
options = options || {};

model = clone(model);
if(!model.required) model.required = [];
Expand All @@ -67,7 +69,12 @@ function validateModel(candidate, model, models){
Object.keys(candidate).forEach(function(propertyName){
var property = model.properties[propertyName];

if(property === undefined) return;
if(property === undefined) {
if( options.checkUnexpectedValues ) {
errors.push(new ValidationError(propertyName, propertyName, new UnexpectedValueError()));
}
return;
}

var error = validate.dataType(candidate[propertyName], property, models);
if(error){
Expand All @@ -79,4 +86,4 @@ function validateModel(candidate, model, models){
return new ValidationErrors(candidate, model.id, model, errors);
}
}
module.exports = validateModel;
module.exports = validateModel;
48 changes: 43 additions & 5 deletions src/validatePrimitiveTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,28 @@

var errorTypes = require('./errorTypes');

function validateInteger(candidate, dataType){
var error = validateNumber(candidate, dataType);
if(error) return error;
function validateInteger(candidate, dataType, format){
var error;
if( !format ) {
error = validateNumber(candidate, dataType);
}
else if(format === 'int32') {
var int32Max = Math.pow(2, 31) - 1;
var int32Value = parseInt(candidate);
if(isNaN(int32Value) || !isFinite(candidate) || int32Value < -(int32Max + 1) || int32Value > int32Max) {
error = new errorTypes.NotANumberError(candidate, typeof candidate);
}
}
else if(format === 'int64') {
var int64Value = parseInt(candidate);
if(isNaN(int64Value) || !isFinite(candidate)) {
error = new errorTypes.NotANumberError(candidate, typeof candidate);
}
}

if(error) {
return error;
}

if(candidate % 1){
return new errorTypes.NotAnIntegerError(candidate);
Expand Down Expand Up @@ -47,7 +66,7 @@ function validateFile(){
}
exports.validateFile = validateFile;

function validateString(candidate, dataType){
function validateString(candidate, dataType, format, pattern){
if(typeof candidate !== 'string' && !(candidate instanceof String)){
return new errorTypes.NotAStringError(candidate, typeof candidate);
}
Expand All @@ -57,5 +76,24 @@ function validateString(candidate, dataType){
return new errorTypes.StringNotInEnumError(candidate, dataType.enum);
}
}

if( format === 'date-time' || format === 'date' ) {
var date = new Date(candidate);
if(date !== 'Invalid Date' && !isNaN(date) && isNaN(candidate)) {
if(format === 'date' && candidate.length !== 10) {
return new errorTypes.NotADateValueError(candidate, typeof candidate);
}
}
else {
return new errorTypes.NotADateValueError(candidate, typeof candidate);
}
}

if( pattern ) {
var regExp = new RegExp(pattern);
if( !regExp.test(candidate) ) {
return new errorTypes.StringFormatNotValidError(candidate, pattern);
}
}
}
exports.validateString = validateString;
exports.validateString = validateString;