182 lines
6.7 KiB
JavaScript
182 lines
6.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.Predicate = exports.validatorSymbol = void 0;
|
|
const is_1 = require("@sindresorhus/is");
|
|
const argument_error_1 = require("../argument-error");
|
|
const not_1 = require("../operators/not");
|
|
const base_predicate_1 = require("./base-predicate");
|
|
const generate_argument_error_message_1 = require("../utils/generate-argument-error-message");
|
|
/**
|
|
@hidden
|
|
*/
|
|
exports.validatorSymbol = Symbol('validators');
|
|
/**
|
|
@hidden
|
|
*/
|
|
class Predicate {
|
|
constructor(type, options = {}) {
|
|
Object.defineProperty(this, "type", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: type
|
|
});
|
|
Object.defineProperty(this, "options", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: options
|
|
});
|
|
Object.defineProperty(this, "context", {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: {
|
|
validators: []
|
|
}
|
|
});
|
|
this.context = {
|
|
...this.context,
|
|
...this.options
|
|
};
|
|
const typeString = this.type.charAt(0).toLowerCase() + this.type.slice(1);
|
|
this.addValidator({
|
|
message: (value, label) => {
|
|
// We do not include type in this label as we do for other messages, because it would be redundant.
|
|
const label_ = label === null || label === void 0 ? void 0 : label.slice(this.type.length + 1);
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
return `Expected ${label_ || 'argument'} to be of type \`${this.type}\` but received type \`${is_1.default(value)}\``;
|
|
},
|
|
validator: value => is_1.default[typeString](value)
|
|
});
|
|
}
|
|
/**
|
|
@hidden
|
|
*/
|
|
[base_predicate_1.testSymbol](value, main, label, idLabel) {
|
|
// Create a map of labels -> received errors.
|
|
const errors = new Map();
|
|
for (const { validator, message } of this.context.validators) {
|
|
if (this.options.optional === true && value === undefined) {
|
|
continue;
|
|
}
|
|
let result;
|
|
try {
|
|
result = validator(value);
|
|
}
|
|
catch (error) {
|
|
// Any errors caught means validators couldn't process the input.
|
|
result = error;
|
|
}
|
|
if (result === true) {
|
|
continue;
|
|
}
|
|
const label2 = is_1.default.function_(label) ? label() : label;
|
|
const labelWithTick = (label2 && idLabel) ? `\`${label2}\`` : label2;
|
|
const label_ = labelWithTick ?
|
|
`${this.type} ${labelWithTick}` :
|
|
this.type;
|
|
const mapKey = label2 || this.type;
|
|
// Get the current errors encountered for this label.
|
|
const currentErrors = errors.get(mapKey);
|
|
// Pre-generate the error message that will be reported to the user.
|
|
const errorMessage = message(value, label_, result);
|
|
// If we already have any errors for this label.
|
|
if (currentErrors) {
|
|
// If we don't already have this error logged, add it.
|
|
currentErrors.add(errorMessage);
|
|
}
|
|
else {
|
|
// Set this label and error in the full map.
|
|
errors.set(mapKey, new Set([errorMessage]));
|
|
}
|
|
}
|
|
// If we have any errors to report, throw.
|
|
if (errors.size > 0) {
|
|
// Generate the `error.message` property.
|
|
const message = generate_argument_error_message_1.generateArgumentErrorMessage(errors);
|
|
throw new argument_error_1.ArgumentError(message, main, errors);
|
|
}
|
|
}
|
|
/**
|
|
@hidden
|
|
*/
|
|
get [exports.validatorSymbol]() {
|
|
return this.context.validators;
|
|
}
|
|
/**
|
|
Invert the following validators.
|
|
*/
|
|
get not() {
|
|
return not_1.not(this);
|
|
}
|
|
/**
|
|
Test if the value matches a custom validation function. The validation function should return an object containing a `validator` and `message`. If the `validator` is `false`, the validation fails and the `message` will be used as error message. If the `message` is a function, the function is invoked with the `label` as argument to let you further customize the error message.
|
|
|
|
@param customValidator - Custom validation function.
|
|
*/
|
|
validate(customValidator) {
|
|
return this.addValidator({
|
|
message: (_, label, error) => typeof error === 'string' ?
|
|
`(${label}) ${error}` :
|
|
error(label),
|
|
validator: value => {
|
|
const { message, validator } = customValidator(value);
|
|
if (validator) {
|
|
return true;
|
|
}
|
|
return message;
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
Test if the value matches a custom validation function. The validation function should return `true` if the value passes the function. If the function either returns `false` or a string, the function fails and the string will be used as error message.
|
|
|
|
@param validator - Validation function.
|
|
*/
|
|
is(validator) {
|
|
return this.addValidator({
|
|
message: (value, label, error) => (error ?
|
|
`(${label}) ${error}` :
|
|
`Expected ${label} \`${value}\` to pass custom validation function`),
|
|
validator
|
|
});
|
|
}
|
|
/**
|
|
Provide a new error message to be thrown when the validation fails.
|
|
|
|
@param newMessage - Either a string containing the new message or a function returning the new message.
|
|
|
|
@example
|
|
```
|
|
ow('🌈', 'unicorn', ow.string.equals('🦄').message('Expected unicorn, got rainbow'));
|
|
//=> ArgumentError: Expected unicorn, got rainbow
|
|
```
|
|
|
|
@example
|
|
```
|
|
ow('🌈', ow.string.minLength(5).message((value, label) => `Expected ${label}, to have a minimum length of 5, got \`${value}\``));
|
|
//=> ArgumentError: Expected string, to be have a minimum length of 5, got `🌈`
|
|
```
|
|
*/
|
|
message(newMessage) {
|
|
const { validators } = this.context;
|
|
validators[validators.length - 1].message = (value, label) => {
|
|
if (typeof newMessage === 'function') {
|
|
return newMessage(value, label);
|
|
}
|
|
return newMessage;
|
|
};
|
|
return this;
|
|
}
|
|
/**
|
|
Register a new validator.
|
|
|
|
@param validator - Validator to register.
|
|
*/
|
|
addValidator(validator) {
|
|
this.context.validators.push(validator);
|
|
return this;
|
|
}
|
|
}
|
|
exports.Predicate = Predicate;
|