dat-middleware
Advanced tools
Comparing version 1.4.0 to 1.5.0
@@ -6,2 +6,4 @@ var error = require('./error'); | ||
var pick = require('101/pick'); | ||
var Boom = require('boom'); | ||
var clone = require('clone'); | ||
var pluck = require('101/pluck'); | ||
@@ -18,3 +20,11 @@ var notEquals = function (compare) { | ||
}; | ||
var arrayToString = function (arr, conjunction, after) { | ||
arr = clone(arr); | ||
var last = '"'+arr.pop()+'"'; | ||
return (arr.length === 0) ? | ||
last : | ||
['"'+arr.join('", "')+'"', conjunction, last, after].join(' '); | ||
}; | ||
var or = utils.or; | ||
@@ -57,3 +67,14 @@ var ternary = utils.ternary; | ||
RequestData.prototype.keys = function (/* ...keys */) { | ||
this._keys = Array.prototype.slice.call(arguments); | ||
if (typeof arguments[0] === 'object') { | ||
if (arguments[0].or) { | ||
this._keys = arguments[0].or; | ||
this.orTheValidations = true; | ||
} | ||
else { | ||
throw new TypeError('invalid key format'); | ||
} | ||
} | ||
else { | ||
this._keys = Array.prototype.slice.call(arguments); | ||
} | ||
@@ -68,2 +89,5 @@ return this; | ||
var errors = []; | ||
if (this.orTheValidations) { | ||
this.execValidationsWithOr(req, res, next); | ||
} | ||
if (this.nextOnFirstError) { | ||
@@ -115,2 +139,33 @@ var errored = this.steps.some(some); | ||
*/ | ||
RequestData.prototype.execValidationsWithOr = function (req, res, next) { | ||
this.steps = this.steps.map(replaceValidationsWithOr); | ||
var keys = this._keys; | ||
var keypath = this.keypath.bind(this); | ||
var dataType = this.dataType; | ||
var dataName = this.dataName + (this.keys.length ? 's' : ''); | ||
function replaceValidationsWithOr (step) { | ||
return { | ||
type: step.type, | ||
validate: function () { | ||
var err; | ||
keys | ||
.map(keypath) | ||
.map(reqValueForKeypath) | ||
.some(function (val) { | ||
err = step.validate(val); | ||
return !err; | ||
}); | ||
if (err) { | ||
return Boom.badRequest(dataName+' '+arrayToString(keys, 'or', err.message)); | ||
} | ||
} | ||
}; | ||
} | ||
function reqValueForKeypath (keypath) { | ||
return keypather.get(req, keypath); | ||
} | ||
}; | ||
/** | ||
* @method | ||
*/ | ||
RequestData.prototype.all = function () { | ||
@@ -366,9 +421,13 @@ this.nextOnFirstError = false; | ||
var keypath = this.keypath.bind(this); | ||
var dataTypeRE = new RegExp('^'+this.dataType+'.'); | ||
var filter = this.required ? | ||
returnTrue : reqValueNotUndefined; | ||
if (this.nextOnFirstError) { | ||
var keys = this._keys | ||
if (this.orTheValidations) { | ||
return step.validate(); | ||
} | ||
else if (this.nextOnFirstError) { | ||
var keypaths = this._keys | ||
.map(keypath) | ||
.filter(filter); | ||
keys | ||
keypaths | ||
.map(reqValueForKeypath) | ||
@@ -402,3 +461,3 @@ .some(firstError); | ||
function formatError (err, i) { | ||
var key = keys[i]; | ||
var key = keypaths[i].replace(dataTypeRE, ''); | ||
err.message = [self.dataName, '"'+key+'"', err.message].join(' ').trim(); | ||
@@ -451,2 +510,2 @@ return err; | ||
return requestData; | ||
}; | ||
}; |
{ | ||
"name": "dat-middleware", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "common request, response, body, query, and param validation, transformation, and flow control middleware", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -19,2 +19,6 @@ var createAppWithMiddleware = require('./fixtures/createAppWithMiddleware'); | ||
describe('mw.params(keys...).require()', requireKeys('params')); | ||
describe('mw.body({ or: [keys...] }).require()', requireKeysOr('body')); | ||
describe('mw.query({ or: [keys...] }).require()', requireKeysOr('query')); | ||
describe('mw.params({ or: [keys...] }).require()', requireKeysOr('params')); | ||
}); | ||
@@ -125,2 +129,53 @@ | ||
}; | ||
} | ||
function requireKeysOr (dataType) { | ||
return function () { | ||
beforeEach(function () { | ||
var keys = this.keys = ['key1', 'key2']; | ||
this.app = createAppWithMiddleware(mw[dataType]({ or: [keys[0], keys[1]] }).require()); | ||
}); | ||
it('should error if all keys are not included', function (done) { | ||
var keys = this.keys; | ||
var body = {}; | ||
var query = {}; | ||
var params = values({}); | ||
request(this.app) | ||
.post('/'+dataType, params, query) | ||
.send(body) | ||
.expect(400) | ||
.expect(function (res) { | ||
keys.forEach(function (key) { | ||
res.body.message.should.match(new RegExp(key)); | ||
}); | ||
res.body.message.should.match(/required/); | ||
}) | ||
.end(done); | ||
}); | ||
it('should pass if one required key is included', function (done) { | ||
var keys = this.keys; | ||
var count = createCounter(done); | ||
var data1 = {}; | ||
data1[keys[0]] = 'value1'; | ||
var body1 = dataType === 'body' ? data1 : {}; | ||
var query1 = dataType === 'query' ? data1 : {}; | ||
var params1 = dataType === 'params' ? values(data1) : []; | ||
request(this.app) | ||
.post('/'+dataType, params1, query1) | ||
.send(body1) | ||
.expect(200) | ||
.end(count.inc().next); | ||
if (dataType !== 'params') { // not possible for params to have middle param missing | ||
var data2 = {}; | ||
data2[keys[1]] = 'value2'; | ||
var body2 = dataType === 'body' ? data2 : {}; | ||
var query2 = dataType === 'query' ? data2 : {}; | ||
request(this.app) | ||
.post('/'+dataType, query2) | ||
.send(body2) | ||
.expect(200) | ||
.end(count.inc().next); | ||
} | ||
}); | ||
}; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
70332
25
1519