logitar-validation
Version:
JavaScript validation library distributed by Logitar.
227 lines (226 loc) • 8.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const logitar_js_1 = require("logitar-js");
const format_1 = require("./format");
const { isNullOrWhiteSpace } = logitar_js_1.stringUtils;
/**
* Applies the execution outcome of a validation rule to a result.
* @param result The result to apply the execution outcome to.
* @param outcome The execution outcome of the validation rule execution.
* @param options The options of the validation rule execution.
*/
function apply(result, outcome, options) {
// severity
result.severity = outcome.severity;
// key
if (!isNullOrWhiteSpace(options.key)) {
result.key = options.key;
}
else if (!isNullOrWhiteSpace(outcome.key)) {
result.key = outcome.key;
}
// message
if (!isNullOrWhiteSpace(options.message)) {
result.message = options.message;
}
else if (!isNullOrWhiteSpace(outcome.message)) {
result.message = outcome.message;
}
// name
if (!isNullOrWhiteSpace(outcome.name)) {
result.name = outcome.name;
}
// value
if (typeof outcome.value !== "undefined") {
result.value = outcome.value;
}
// custom
result.custom = outcome.custom;
}
/**
* Fills the placeholders of a validation rule execution.
* @param result The result to fill the placeholders of.
* @param outcome The execution outcome of the validation rule.
* @param rule The options of the validation rule execution.
* @param validation The options of the validation operation.
*/
function fillPlaceholders(result, outcome, rule, validation) {
result.placeholders.key = result.key;
result.placeholders.name = result.name;
result.placeholders.value = result.value;
result.placeholders.severity = result.severity;
if (outcome && outcome.placeholders) {
result.placeholders = Object.assign(Object.assign({}, result.placeholders), outcome.placeholders);
}
if (rule && rule.placeholders) {
result.placeholders = Object.assign(Object.assign({}, result.placeholders), rule.placeholders);
}
if (validation && validation.placeholders) {
result.placeholders = Object.assign(Object.assign({}, result.placeholders), validation.placeholders);
}
}
/**
* A validator is a collection of validation rules that can be executed on a value.
*/
class Validator {
/**
* Initializes a new instance of the Validator class.
* @param options The options of the validator.
*/
constructor(options) {
var _a, _b, _c;
options !== null && options !== void 0 ? options : (options = {});
this.messageFormatter = (_a = options.messageFormatter) !== null && _a !== void 0 ? _a : new format_1.DefaultMessageFormatter();
this.rules = new Map();
this.throwOnFailure = (_b = options.throwOnFailure) !== null && _b !== void 0 ? _b : false;
this.treatWarningsAsErrors = (_c = options.treatWarningsAsErrors) !== null && _c !== void 0 ? _c : false;
}
/**
* Clears all the rules registered to this validator.
*/
clearRules() {
this.rules.clear();
}
/**
* Gets a rule from the validator.
* @param key The key of the rule to get.
* @returns The rule configuration.
*/
getRule(key) {
return this.rules.get(key);
}
/**
* Checks if a rule is registered to this validator.
* @param key The key of the rule to check.
* @returns A value indicating whether the rule is registered to this validator.
*/
hasRule(key) {
return this.rules.has(key);
}
/**
* Lists all the rules registered to this validator.
* @returns The rules registered to this validator.
*/
listRules() {
return [...this.rules.entries()];
}
/**
* Removes a rule from the validator.
* @param key The key of the rule to remove.
* @returns A value indicating whether the rule was removed from the validator.
*/
removeRule(key) {
return this.rules.delete(key);
}
/**
* Registers a rule to the validator.
* @param key The key of the rule to register.
* @param rule The rule to register.
* @param options The options of the rule.
*/
setRule(key, rule, options) {
options !== null && options !== void 0 ? options : (options = {});
const configuration = { rule, options };
this.rules.set(key, configuration);
}
/**
* Validates a field/property against a set of rules.
* @param name The name of the field/property to validate.
* @param value The value of the field/property to validate.
* @param rules The rule set to validate the value against.
* @param options The options of the validation operation.
* @returns The result of the validation operation.
*/
validate(name, value, rules, options) {
var _a, _b;
options !== null && options !== void 0 ? options : (options = {});
const context = (_a = options.context) !== null && _a !== void 0 ? _a : {};
let errors = 0;
const results = {};
const missingRules = [];
for (const key in rules) {
const configuration = this.rules.get(key);
if (!configuration) {
missingRules.push(key);
continue;
}
const args = rules[key];
if (typeof args === "undefined" || args === null || args === false || args === "" || (typeof args === "number" && isNaN(args))) {
// NOTE(fpion): 0, -0 and 0n (BigInt) are considered valid arguments.
continue;
}
const result = {
key,
severity: "error",
placeholders: { [key]: args },
name,
value,
};
const outcome = configuration.rule(value, args, context);
switch (typeof outcome) {
case "boolean":
result.severity = Boolean(outcome) ? "information" : "error";
break;
case "string":
result.severity = outcome;
break;
default:
apply(result, outcome, configuration.options);
break;
}
fillPlaceholders(result, typeof outcome === "object" ? outcome : undefined, configuration.options, options);
this.formatMessage(result, options);
if (this.isError(result.severity, options)) {
errors++;
}
results[key] = result;
}
if (missingRules.length > 0) {
throw new Error(`The following rules are not registered: ${missingRules.join(", ")}`);
}
const result = {
isValid: errors === 0,
rules: results,
context,
};
if (!result.isValid && ((_b = options.throwOnFailure) !== null && _b !== void 0 ? _b : this.throwOnFailure)) {
throw result;
}
return result;
}
/**
* Formats a validation rule execution message.
* @param result The result to format the message of.
* @param options The options of the validation operation.
*/
formatMessage(result, options) {
var _a;
options !== null && options !== void 0 ? options : (options = {});
const messageFormatter = (_a = options.messageFormatter) !== null && _a !== void 0 ? _a : this.messageFormatter;
if (typeof result.message === "string") {
result.message = messageFormatter.format(result.message, result.placeholders);
}
}
/**
* Checks if a severity is an error.
* @param severity The severity to check.
* @param options The options of the validation operation.
* @returns A value indicating whether the severity is an error.
*/
isError(severity, options) {
var _a;
options !== null && options !== void 0 ? options : (options = {});
switch (severity) {
case "error":
case "critical":
return true;
case "warning":
if ((_a = options.treatWarningsAsErrors) !== null && _a !== void 0 ? _a : this.treatWarningsAsErrors) {
return true;
}
break;
}
return false;
}
}
exports.default = Validator;