@naturalcycles/nodejs-lib
Version:
Standard library for Node.js
125 lines • 4.49 kB
JavaScript
;
/*
* Does 2 things:
* 1. Validates the value according to Schema passed.
* 2. Converts the value (also according to Schema).
*
* "Converts" mean e.g trims all strings from leading/trailing spaces.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const js_lib_1 = require("@naturalcycles/js-lib");
const joi_extensions_1 = require("./joi.extensions");
const joi_validation_error_1 = require("./joi.validation.error");
// Strip colors in production (for e.g Sentry reporting)
const stripColors = process.env.NODE_ENV === 'production';
const defaultOptions = {
abortEarly: false,
convert: true,
allowUnknown: true,
stripUnknown: {
objects: true,
// true: it will SILENTLY strip invalid values from arrays. Very dangerous! Can lead to data loss!
// false: it will THROW validation error if any of array items is invalid
// Q: is it invalid if it has unknown properties?
// A: no, unknown properties are just stripped (in both 'false' and 'true' states), array is still valid
// Q: will it strip or keep unknown properties in array items?..
// A: strip
arrays: false,
},
presence: 'required',
};
/**
* Validates with Joi.
* Throws AppValidationError if invalid.
* Returns *converted* value.
*
* If `schema` is undefined - returns value as is.
*/
function validate(value, schema, objectName, options = {}) {
const { value: returnValue, error } = getValidationResult(value, schema, objectName, options);
if (error) {
throw error;
}
return returnValue;
}
exports.validate = validate;
/**
* Validates with Joi.
* Returns ValidationResult with converted value and error (if any).
* Does not throw.
*
* If `schema` is undefined - returns value as is.
*/
function getValidationResult(value, schema, objectName, options = {}) {
if (!schema)
return { value };
const { value: returnValue, error } = joi_extensions_1.Joi.validate(value, schema, {
...defaultOptions,
...options,
});
const vr = {
value: returnValue,
};
if (error) {
vr.error = createError(value, error, objectName);
}
return vr;
}
exports.getValidationResult = getValidationResult;
/**
* Convenience function that returns true if !error.
*/
function isValid(value, schema) {
if (!schema)
return { value };
const { error } = joi_extensions_1.Joi.validate(value, schema, defaultOptions);
return !error;
}
exports.isValid = isValid;
function undefinedIfInvalid(value, schema) {
if (!schema)
return { value };
const { value: returnValue, error } = joi_extensions_1.Joi.validate(value, schema, defaultOptions);
return error ? undefined : returnValue;
}
exports.undefinedIfInvalid = undefinedIfInvalid;
/**
* Will do joi-convertation, regardless of error/validity of value.
* @returns converted value
*/
function convert(value, schema) {
if (!schema)
return value;
const { value: returnValue } = joi_extensions_1.Joi.validate(value, schema, defaultOptions);
return returnValue;
}
exports.convert = convert;
function createError(value, err, objectName) {
if (!err)
return undefined;
const tokens = [];
const objectId = js_lib_1.isObject(value) ? value['id'] : undefined;
if (objectId || objectName) {
objectName = objectName || (value && value.constructor && value.constructor.name);
tokens.push([objectName, objectId].filter(i => i).join('.'));
}
const annotation = err.annotate(stripColors); // typings are not up-to-date, hence "as any"
if (annotation.length > 1000) {
// Annotation message is too big and will be replaced by stringified `error.details` instead
tokens.push(annotation.substr(0, 1000), `... ${Math.ceil(annotation.length / 1024)} KB message truncated`);
// Up to 5 `details`
tokens.push(...err.details.slice(0, 5).map(i => `${i.message} @ .${i.path.join('.')}`));
if (err.details.length > 5)
tokens.push(`... ${err.details.length} errors`);
}
else {
tokens.push(annotation);
}
const msg = tokens.join('\n');
return new joi_validation_error_1.JoiValidationError(msg, {
joiValidationErrorItems: err.details,
...(objectName && { joiValidationObjectName: objectName }),
...(objectId && { joiValidationObjectId: objectId }),
});
}
//# sourceMappingURL=joi.validation.util.js.map