Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
TGOlson committed Aug 25, 2015
1 parent e342c31 commit e13c65e
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 73 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var V = require('o-validator');
var R = require('ramda');

var hasLengthGreaterThan = R.curry(function(n, x) {
return R.propSatisfies(R.lt(n), 'length');
return R.propSatisfies(R.lt(n), 'length', x);
});

var schema = {
Expand Down Expand Up @@ -153,10 +153,10 @@ Error codes that define the type of validation error that was found. Used to pop

```js
{
REQUIRED : 'Required',
UNSUPPORTED : 'Unsupported',
VALUE : 'Value',
UNKNOWN : 'Unknown'
REQUIRED : 'REQUIRED',
UNSUPPORTED : 'UNSUPPORTED',
VALUE : 'VALUE',
UNKNOWN : 'UNKNOWN'
}
```

Expand Down
11 changes: 6 additions & 5 deletions lib/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ var Err = require('./validator/errors');
/**
* Types:
*
* Predicate :: a -> Boolean
* Schema :: {k: Predicate}
* ErrorObject :: {property: String, errorCode: String}
* ErrorObjectWithMessage :: {property: String, errorCode: String, message: String}
* Predicate (a -> Boolean)
* Schema {k: Predicate}
* ErrorObject {property: String, errorCode: String}
* ErrorObjectWithMessage {property: String, errorCode: String, message: String}
*/


Expand Down Expand Up @@ -44,6 +44,7 @@ module.exports = {
/**
* Throws an error containing information about any validation errors, if
* found. Otherwise returns the original input arguments.
*
* Schema -> Object -> Error or Object
*/
validateOrThrow : Core.validateWithErrorHandler(
Expand Down Expand Up @@ -83,5 +84,5 @@ module.exports = {
*
* (type not exposed, implementation details are internal to this library)
*/
required : Core.annotatePredicateAsRequired
required : Core.annotateAsRequired
};
8 changes: 4 additions & 4 deletions lib/validator/constants.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module.exports = {
errorCodes: {
REQUIRED : 'Required',
UNSUPPORTED : 'Unsupported',
VALUE : 'Value',
UNKNOWN : 'Unknown'
REQUIRED : 'REQUIRED',
UNSUPPORTED : 'UNSUPPORTED',
VALUE : 'VALUE',
UNKNOWN : 'UNKNOWN'
},
errorMessages: {
REQUIRED : 'Missing required parameter',
Expand Down
74 changes: 31 additions & 43 deletions lib/validator/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,53 @@ var R = require('ramda');
var Err = require('./errors');


var annotatePredicate = R.curry(function(annotation, predicate) {
var annotate = R.curry(function(annotation, predicate) {
return R.merge(annotation, {predicate : predicate});
});


var annotatePredicateAsRequired = annotatePredicate({required: true});
var annotatePredicateAsOptional = annotatePredicate({required: false});
var annotateAsRequired = annotate({required: true});
var annotateAsOptional = annotate({required: false});
var emptyAnnotatedPredicate = annotateAsOptional(undefined);


var makeEmptyAnnotatedPredicate = R.always(annotatePredicateAsOptional(undefined));
var maybeAnnotatePredicate = R.ifElse(R.is(Function), annotateAsOptional, R.identity);


var maybeAnnotatePredicate = R.ifElse(R.is(Function), annotatePredicateAsOptional, R.identity);


var annotatePredicateWithResult = R.curry(function(values, predicate, property) {
var annotatedPredicate = maybeAnnotatePredicate(predicate);
var value = values[property];

return R.merge(annotatedPredicate, {
value : value,
property : property,
result : annotatedPredicate.predicate ? annotatedPredicate.predicate(value) : undefined
var annotateWithResult = function(annotatedP) {
return R.merge(annotatedP, {
result: annotatedP.predicate ? annotatedP.predicate(annotatedP.value) : undefined
});
});


// [Predicate] -> [a] -> [AnnotatedPredicateWithResults]
function annotatePredicatesWithResults(predicates, values) {
var unsupportedParameters = getUnsupportedParameters(predicates, values),
allPredicates = R.merge(predicates, unsupportedParameters);

return R.values(R.mapObjIndexed(annotatePredicateWithResult(values), allPredicates));
}
};


function getUnsupportedParameters(predicates, values) {
var annotateWithPropVals = R.curry(function(annotatedPs, values) {
return R.mapObjIndexed(function(pred, prop) {
return R.merge(pred, {property: prop, value: values[prop]});
}, annotatedPs);
});

// Find all the parameters that are defined in the value set, but not in the predicates
// these will be the unsupported parameters
var unSupportedParameters = R.filter(R.complement(R.has(R.__, predicates)), R.keys(values));

return R.zipObj(unSupportedParameters, R.map(makeEmptyAnnotatedPredicate, unSupportedParameters));
}
var addUnsupportedParameters = function(predicates, values) {
var unsupportedParameters = R.reject(R.has(R.__, predicates), R.keys(values));
return R.assoc(unsupportedParameters, emptyAnnotatedPredicate, predicates);
};


function annotateWithDefaultErrorMessage(a) {
var annotateWithDefaultErrorMessage = function(a) {
return R.merge(a, {message: Err.getDefaultErrorMessage(a)});
}
};


var validateWithHandlers = R.curry(function(successHandler, errorHandler, schema, data) {
var annotatedPs = R.mapObj(maybeAnnotatePredicate, schema);
var allPredicates = addUnsupportedParameters(annotatedPs, data);
var predList = R.values(annotateWithPropVals(allPredicates, data));

// keep success handler portion of API internal
// validation functions should (and will) always return original args
// unless other functionality is explicitly provided by this library
var validateWithHandlers = R.curry(function(successHandler, errorHandler, schema, props) {
var results = annotatePredicatesWithResults(schema, props);
var results = R.map(annotateWithResult, predList);
var errors = Err.getErrors(results);

return R.isEmpty(errors) ? successHandler(props) : errorHandler(errors);
return R.isEmpty(errors) ? successHandler(data) : errorHandler(errors);
});


Expand All @@ -74,8 +62,8 @@ var addDefaultErrorMessages = R.map(annotateWithDefaultErrorMessage);


module.exports = {
validateWithHandlers : validateWithHandlers,
validateWithErrorHandler : validateWithErrorHandler,
addDefaultErrorMessages : addDefaultErrorMessages,
annotatePredicateAsRequired : annotatePredicateAsRequired,
validateWithHandlers : validateWithHandlers,
validateWithErrorHandler : validateWithErrorHandler,
addDefaultErrorMessages : addDefaultErrorMessages,
annotateAsRequired : annotateAsRequired
};
7 changes: 0 additions & 7 deletions lib/validator/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ var errorCodes = Constant.errorCodes;
var errorMessages = Constant.errorMessages;


// AnnotatedPredicateWithResults -> String
var getErrorType = R.cond([
[Result.isRequiredWithUndefinedValue, R.always(errorCodes.REQUIRED)],
[Result.hasUndefinedPredicate, R.always(errorCodes.UNSUPPORTED)],
Expand All @@ -19,7 +18,6 @@ var getErrorType = R.cond([
]);


// AnnotatedPredicateWithResults -> AnnotatedPredicateWithResults
var annotateErrorCode = function(annotatedPredicate) {
return {
property : annotatedPredicate.property,
Expand All @@ -28,14 +26,12 @@ var annotateErrorCode = function(annotatedPredicate) {
};


// [AnnotatedPredicateWithResults] -> [AnnotatedPredicateWithResults]
var getErrors = R.compose(
R.map(annotateErrorCode),
R.reject(Result.isPassingResult)
);


// String -> String
var getDefaultErrorPrefix = R.cond([
[R.equals(errorCodes.REQUIRED), R.always(errorMessages.REQUIRED)],
[R.equals(errorCodes.UNSUPPORTED), R.always(errorMessages.UNSUPPORTED)],
Expand All @@ -44,19 +40,16 @@ var getDefaultErrorPrefix = R.cond([
]);


// AnnotatedPredicateWithResults -> String
var getDefaultErrorMessage = function(annotatedPredicate) {
return getDefaultErrorPrefix(annotatedPredicate.errorCode) + ' "' + annotatedPredicate.property + '"';
};


// String -> Error
var throwError = function(msg) {
throw new Error('Validation Error: ' + msg);
};


// [AnnotatedPredicateWithResults] -> Error
var throwValidationErrors = R.compose(throwError, R.join(', '), R.pluck('message'));


Expand Down
6 changes: 0 additions & 6 deletions lib/validator/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,27 @@ var R = require('ramda');
*/


// AnnotatedPredicateWithResults -> Boolean
var isRequiredWithUndefinedValue = R.allPass([
R.propEq('required', true),
R.propEq('value', undefined)
]);


// AnnotatedPredicateWithResults -> Boolean
var hasUndefinedPredicate = R.propEq('predicate', undefined);


// AnnotatedPredicateWithResults -> Boolean
var hasDefinedValueWithFalseResult = R.allPass([
R.complement(R.propEq('value', undefined)),
R.propEq('result', false)
]);


// AnnotatedPredicateWithResults -> Boolean
var satisfiedPredicate = R.propEq('result', true);


// AnnotatedPredicateWithResults -> Boolean
var isOptionallyOmmitted = R.allPass([R.propEq('required', false), R.propEq('value', undefined)]);


// AnnotatedPredicateWithResults -> Boolean
var isPassingResult = R.anyPass([satisfiedPredicate, isOptionallyOmmitted]);


Expand Down
17 changes: 14 additions & 3 deletions spec/validator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,19 @@ describe('Validator', function() {
describe('getErrors', function() {
var expectedTitleRequiredError = {
property : 'title',
errorCode : 'Required',
errorCode : 'REQUIRED',
message : 'Missing required parameter "title"'
};

var expectedDescriptionValueError = {
property : 'description',
errorCode : 'Value',
errorCode : 'VALUE',
message : 'Illegal value for parameter "description"'
};

var expectedIsAdminUnsupportedError = {
property : 'isAdmin',
errorCode : 'Unsupported',
errorCode : 'UNSUPPORTED',
message : 'Unsupported parameter "isAdmin"'
};

Expand Down Expand Up @@ -182,4 +182,15 @@ describe('Validator', function() {
expect(Validator.validateOrThrow(pattern, args)).toBe(args);
});
});

describe('errorCodes', function() {
it('should be a set of error codes', function() {
expect(Validator.errorCodes).toEqual({
REQUIRED : 'REQUIRED',
UNSUPPORTED : 'UNSUPPORTED',
VALUE : 'VALUE',
UNKNOWN : 'UNKNOWN'
});
});
});
});

0 comments on commit e13c65e

Please sign in to comment.