const validator = require('validator'); const runner = require('./runner'); const { isSanitizer, isValidator } = require('../utils/filters'); module.exports = (fields, locations, message) => { let optional; const validators = []; const sanitizers = []; fields = Array.isArray(fields) ? fields : [fields]; const middleware = (req, res, next) => { return runner(req, middleware._context).then(errors => { req._validationContexts = (req._validationContexts || []).concat(middleware._context); req._validationErrors = (req._validationErrors || []).concat(errors); next(); }, next); }; Object.keys(validator) .filter(isValidator) .forEach(methodName => { const validationFn = validator[methodName]; middleware[methodName] = (...options) => { validators.push({ negated: middleware._context.negateNext, validator: validationFn, options }); middleware._context.negateNext = false; return middleware; }; }); Object.keys(validator) .filter(isSanitizer) .forEach(methodName => { const sanitizerFn = validator[methodName]; middleware[methodName] = (...options) => { sanitizers.push({ sanitizer: sanitizerFn, options }); return middleware; }; }); middleware.optional = (options = {}) => { optional = options; return middleware; }; middleware.custom = validator => { validators.push({ validator, custom: true, negated: middleware._context.negateNext, options: [] }); middleware._context.negateNext = false; return middleware; }; middleware.customSanitizer = sanitizer => { sanitizers.push({ sanitizer, custom: true, options: [] }); return middleware; }; middleware.exists = (options = {}) => { const validator = options.checkFalsy ? existsValidatorCheckFalsy : (options.checkNull ? existsValidatorCheckNull : existsValidator); return middleware.custom(validator); }; middleware.isArray = () => middleware.custom(value => Array.isArray(value)); middleware.isString = () => middleware.custom(value => typeof value === 'string'); middleware.withMessage = message => { const lastValidator = validators[validators.length - 1]; if (lastValidator) { lastValidator.message = message; } return middleware; }; middleware.not = () => { middleware._context.negateNext = true; return middleware; }; middleware._context = { get optional() { return optional; }, negateNext: false, message, fields, locations, sanitizers, validators }; return middleware; }; function existsValidator(value) { return value !== undefined; } function existsValidatorCheckNull(value) { return value != null; } function existsValidatorCheckFalsy(value) { return !!value; }