// eslint-disable-next-line no-shadow-restricted-names
((exports, undefined) => {
const regexps = exports.regexps = {
email: /^.+@.+\..+/i,
// eslint-disable-next-line
url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
};
/**
* @namespace Validators
*/
const validators = exports.validators = {
// most of these are copied from the jquery validation plugin
// http://code.google.com/p/bassistance-plugins/source/browse/trunk/plugins/validate/jquery.validate.js
/**
* Test if the value is alphanumeric or optional (params[0]) and empty
* @memberof Validators
*/
alphanumeric: function alphanumeric(value) {
return Promise.resolve(/^[\w]+$/.test(value));
},
/**
* Make sure a value is a date that the Date object can parse.
* Can be optional.
* @memberof Validators
*/
date: function date(value) {
return Promise.resolve(!/Invalid|NaN/.test((new Date(value)).toString()));
},
/**
* Make sure a value is a valid ISO Date (YYYY-MM-DD) or is optional (params[0]) and empty
* @memberof Validators
*/
dateISO: function dateISO(value) {
return Promise.resolve(/^\d{4}[/-]\d{1,2}[/-]\d{1,2}$/.test(value));
},
/**
* Makes sure a string consists of only numeric digits.
* @memberof Validators
*/
digits: function digits(value) {
return Promise.resolve(/^\d+$/.test(value));
},
/**
* Make sure a value is a valid email adress.
* @memberof Validators
*/
email: function email(value) {
return Promise.resolve(regexps.email.test(value));
},
/**
* String length must be between options.min (default 0) and options.max (default positive infinity).
* @memberof Validators
*/
length: function length(value, options) {
if (options.trim) {
('' + value).trim();
}
const min = value.length >= (options.min || 0);
const max = value.length <= (options.max || Number.POSITIVE_INFINITY);
return Promise.resolve(min && max);
},
/**
* Make sure a number value is between (inclusive) options.min (default: 0)
* and options.max (default: POSITIVE_INFINITY)
* @memberof Validators
*/
minMax: function minMax(value, options) {
value = +value;
const min = value >= (options.min || 0);
const max = value <= (options.max || Number.POSITIVE_INFINITY);
return Promise.resolve(min && max);
},
/**
* Make sure a value is not empty. Any falsy value is considered empty (including 0).
* use minMax for number types instead!
* @memberof Validators
*/
notEmpty: function notEmpty(value, options) {
if (typeof (value) === 'string' && options.trim) {
value = value.trim();
}
return Promise.resolve(!!value);
},
/**
* Make sure a value is a valid (SI, US or EU) number string or is optional (params[0]) and empty
* @memberof Validators
*/
number: function number(value) {
return Promise.resolve(/^-?(?:\d+|\d{1,3}(?:[ ,.]\d{3})+)(?:[,.]\d+)?$/.test(value));
},
/**
* Make sure a value is a valid EU number (thousands seperator point, decimal seperator comma)
* string or is optional (params[0]) and empty
* @memberof Validators
*/
numberEU: function numberEU(value) {
return Promise.resolve(/^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value));
},
/**
* Make sure a value is a valid SI number (thousands seperator space, decimal seperator point or comma)
* string or is optional (params[0]) and empty
* @memberof Validators
*/
numberSI: function numberSI(value) {
return Promise.resolve(/^-?(?:\d+|\d{1,3}(?: \d{3})+)(?:[,.]\d+)?$/.test(value));
},
/**
* Make sure a value is a valid US number (thousands seperator comma, decimal seperator point)
* string or is optional (params[0]) and empty
* @memberof Validators
*/
numberUS: function numberUS(value) {
return Promise.resolve(/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value));
},
/**
* Test if the value matches the provided regexp or optional (params[0]) and empty
* @memberof Validators
*/
regexp: function regexp(value, options) {
if (options.regex instanceof RegExp) {
return Promise.resolve(options.regex.test(value));
} else {
return Promise.reject(new Error('Option for regexp validation was not a RegExp object.'));
}
},
/**
* Make sure a value is a valid url.
* @memberof Validators
*/
url: function url(value) {
return Promise.resolve(regexps.url.test(value));
},
};
// while there are tests for the browser validations, they depend on vm.runInNewContext.
// this creates a sandboxed environment that currently cannot be properly analysed for coverage.
// see ../test/middlewareTests.js for the tests
// see https://github.com/istanbuljs/nyc/issues/371 for details on
/* istanbul ignore if */
if (typeof (window) !== 'undefined' && typeof (nohmValidationsNamespaceName) !== 'undefined') {
// we're in a browser and have a defined namespace
// eslint-disable-next-line
const nohm = window[nohmValidationsNamespaceName];
// get extra validators
for (var i in nohm.extraValidations) {
if (Object.prototype.hasOwnProperty.call(nohm.extraValidations, i)) {
for (var name in nohm.extraValidations[i]) {
if (Object.prototype.hasOwnProperty.call(nohm.extraValidations[i], name)) {
validators[name] = nohm.extraValidations[i][name];
}
}
}
}
var validateProperty = (key, value, validations, cb) => {
var options = {
optional: false,
trim: true
};
var funcs = [];
var wrap = function (func, options, name) {
funcs.push(function () {
if (options.optional && !value) {
return cb(key, true);
}
try {
func(value, options).then((result) => {
cb(key, result, name);
});
} catch (e) {
cb(key, false, name);
}
});
};
for (var i = 0, len = validations.length; i < len; i++) {
var val = validations[i];
if (typeof val === 'string') {
// simple string
if (!validators[val]) {
throw new Error('Trying to access unavailable validator.');
}
wrap(validators[val], options, val);
} else if (val && typeof (val.name) === 'string') {
/*
Validation object
{
name: 'someValidtaor',
options: {
someOption: false
}
}
*/
if (!validators[val.name]) {
throw new Error('Trying to access unavailable validator.');
}
var localOptions = $extend(true, {}, options, val.options);
wrap(validators[val.name], localOptions, val.name);
} else {
throw new Error('Invalid validation definition for property "' + key + '":' + val);
}
}
return funcs;
};
nohm.nohmValidations = validators;
nohm.validate = function (modelName, data) {
if (arguments.length > 0) {
const lastArgument = arguments[arguments.length - 1];
if (typeof lastArgument === 'function') {
throw new Error('Callback style has been removed. Use the returned promise.');
}
}
return new Promise((resolve, reject) => {
if (typeof (modelName) === 'undefined' || typeof (data) === 'undefined') {
return reject(new Error('Invalid input passed to nohm validate() function. Needs a modelname and a data object.'));
}
if (!Object.prototype.hasOwnProperty.call(nohm.models, modelName)) {
return reject(new Error('Invalid modelName passed to nohm or model was not properly exported.'));
}
var model = nohm.models[modelName];
var errors = {};
var failed = false;
var dispatched = 0;
var doneCount = 0;
var funcs = [];
var done = function () {
done = function () { }; // just to be sure :D
resolve({
result: !failed,
errors
});
};
var validCallback = function (key, valid, errorName) {
if (!valid) {
failed = true;
if (!Object.prototype.hasOwnProperty.call(errors, key)) {
errors[key] = [];
}
errors[key].push(errorName);
}
if (++doneCount >= dispatched) {
done();
}
};
for (var key in data) {
if (Object.prototype.hasOwnProperty.call(data, key) && Object.prototype.hasOwnProperty.call(model, key)) {
var innerFuncs = validateProperty(key, data[key], model[key], validCallback);
for (var len = innerFuncs.length, i = 0; i < len; i++) {
funcs.push(innerFuncs[i]);
}
}
}
dispatched = funcs.length;
if (dispatched === 0) {
return done();
}
for (var n = 0; n < dispatched; n++) {
var func = funcs[n];
if (typeof (func) === 'function') {
func(); // this makes sure we first know how many funcs we have before we call them, thus not calling done() too early if all validators are instant
} else {
return resolve(new Error('There were invalid validators'));
}
}
});
};
/**
* This extends an object with x other objects.
* @see http://api.jquery.com/jQuery.extend/
*/
var $extend = function () {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if (typeof target !== "object" && typeof (target) == 'function') {
target = {};
}
for (; i < length; i++) {
// Only deal with non-null/undefined values
if ((options = arguments[i]) !== null) {
// Extend the base object
for (name in options) {
if (Object.prototype.hasOwnProperty.call(options, name)) {
src = target[name];
copy = options[name];
// Prevent never-ending loop
if (target === copy) {
continue;
}
// Recurse if we're merging plain objects or arrays
if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && Array.isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[name] = $extend(deep, clone, copy);
// Don't bring in undefined values
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
}
// Return the modified object
return target;
};
// from jquery as well
var isPlainObject = function (obj) {
// Not own constructor property must be Object
if (obj.constructor &&
!Object.prototype.hasOwnProperty.call(obj, "constructor") &&
!Object.prototype.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
var key;
for (key in obj) {
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
}
return key === undefined || Object.prototype.hasOwnProperty.call(obj, key);
};
}
})(typeof (exports) === 'undefined' ? {} : exports);