1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.Predicate = exports.validatorSymbol = void 0;
|
4 | const is_1 = require("@sindresorhus/is");
|
5 | const argument_error_1 = require("../argument-error");
|
6 | const not_1 = require("../operators/not");
|
7 | const base_predicate_1 = require("./base-predicate");
|
8 | const generate_argument_error_message_1 = require("../utils/generate-argument-error-message");
|
9 | /**
|
10 | @hidden
|
11 | */
|
12 | exports.validatorSymbol = Symbol('validators');
|
13 | /**
|
14 | @hidden
|
15 | */
|
16 | class Predicate {
|
17 | constructor(type, options = {}) {
|
18 | Object.defineProperty(this, "type", {
|
19 | enumerable: true,
|
20 | configurable: true,
|
21 | writable: true,
|
22 | value: type
|
23 | });
|
24 | Object.defineProperty(this, "options", {
|
25 | enumerable: true,
|
26 | configurable: true,
|
27 | writable: true,
|
28 | value: options
|
29 | });
|
30 | Object.defineProperty(this, "context", {
|
31 | enumerable: true,
|
32 | configurable: true,
|
33 | writable: true,
|
34 | value: {
|
35 | validators: []
|
36 | }
|
37 | });
|
38 | this.context = {
|
39 | ...this.context,
|
40 | ...this.options
|
41 | };
|
42 | const typeString = this.type.charAt(0).toLowerCase() + this.type.slice(1);
|
43 | this.addValidator({
|
44 | message: (value, label) => {
|
45 | // We do not include type in this label as we do for other messages, because it would be redundant.
|
46 | const label_ = label === null || label === void 0 ? void 0 : label.slice(this.type.length + 1);
|
47 | // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
48 | return `Expected ${label_ || 'argument'} to be of type \`${this.type}\` but received type \`${is_1.default(value)}\``;
|
49 | },
|
50 | validator: value => is_1.default[typeString](value)
|
51 | });
|
52 | }
|
53 | /**
|
54 | @hidden
|
55 | */
|
56 | [base_predicate_1.testSymbol](value, main, label, idLabel) {
|
57 | // Create a map of labels -> received errors.
|
58 | const errors = new Map();
|
59 | for (const { validator, message } of this.context.validators) {
|
60 | if (this.options.optional === true && value === undefined) {
|
61 | continue;
|
62 | }
|
63 | let result;
|
64 | try {
|
65 | result = validator(value);
|
66 | }
|
67 | catch (error) {
|
68 | // Any errors caught means validators couldn't process the input.
|
69 | result = error;
|
70 | }
|
71 | if (result === true) {
|
72 | continue;
|
73 | }
|
74 | const label2 = is_1.default.function_(label) ? label() : label;
|
75 | const labelWithTick = (label2 && idLabel) ? `\`${label2}\`` : label2;
|
76 | const label_ = labelWithTick ?
|
77 | `${this.type} ${labelWithTick}` :
|
78 | this.type;
|
79 | const mapKey = label2 || this.type;
|
80 | // Get the current errors encountered for this label.
|
81 | const currentErrors = errors.get(mapKey);
|
82 | // Pre-generate the error message that will be reported to the user.
|
83 | const errorMessage = message(value, label_, result);
|
84 | // If we already have any errors for this label.
|
85 | if (currentErrors) {
|
86 | // If we don't already have this error logged, add it.
|
87 | currentErrors.add(errorMessage);
|
88 | }
|
89 | else {
|
90 | // Set this label and error in the full map.
|
91 | errors.set(mapKey, new Set([errorMessage]));
|
92 | }
|
93 | }
|
94 | // If we have any errors to report, throw.
|
95 | if (errors.size > 0) {
|
96 | // Generate the `error.message` property.
|
97 | const message = generate_argument_error_message_1.generateArgumentErrorMessage(errors);
|
98 | throw new argument_error_1.ArgumentError(message, main, errors);
|
99 | }
|
100 | }
|
101 | /**
|
102 | @hidden
|
103 | */
|
104 | get [exports.validatorSymbol]() {
|
105 | return this.context.validators;
|
106 | }
|
107 | /**
|
108 | Invert the following validators.
|
109 | */
|
110 | get not() {
|
111 | return not_1.not(this);
|
112 | }
|
113 | /**
|
114 | 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.
|
115 |
|
116 | @param customValidator - Custom validation function.
|
117 | */
|
118 | validate(customValidator) {
|
119 | return this.addValidator({
|
120 | message: (_, label, error) => typeof error === 'string' ?
|
121 | `(${label}) ${error}` :
|
122 | error(label),
|
123 | validator: value => {
|
124 | const { message, validator } = customValidator(value);
|
125 | if (validator) {
|
126 | return true;
|
127 | }
|
128 | return message;
|
129 | }
|
130 | });
|
131 | }
|
132 | /**
|
133 | 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.
|
134 |
|
135 | @param validator - Validation function.
|
136 | */
|
137 | is(validator) {
|
138 | return this.addValidator({
|
139 | message: (value, label, error) => (error ?
|
140 | `(${label}) ${error}` :
|
141 | `Expected ${label} \`${value}\` to pass custom validation function`),
|
142 | validator
|
143 | });
|
144 | }
|
145 | /**
|
146 | Provide a new error message to be thrown when the validation fails.
|
147 |
|
148 | @param newMessage - Either a string containing the new message or a function returning the new message.
|
149 |
|
150 | @example
|
151 | ```
|
152 | ow('🌈', 'unicorn', ow.string.equals('🦄').message('Expected unicorn, got rainbow'));
|
153 | //=> ArgumentError: Expected unicorn, got rainbow
|
154 | ```
|
155 |
|
156 | @example
|
157 | ```
|
158 | ow('🌈', ow.string.minLength(5).message((value, label) => `Expected ${label}, to have a minimum length of 5, got \`${value}\``));
|
159 | //=> ArgumentError: Expected string, to be have a minimum length of 5, got `🌈`
|
160 | ```
|
161 | */
|
162 | message(newMessage) {
|
163 | const { validators } = this.context;
|
164 | validators[validators.length - 1].message = (value, label) => {
|
165 | if (typeof newMessage === 'function') {
|
166 | return newMessage(value, label);
|
167 | }
|
168 | return newMessage;
|
169 | };
|
170 | return this;
|
171 | }
|
172 | /**
|
173 | Register a new validator.
|
174 |
|
175 | @param validator - Validator to register.
|
176 | */
|
177 | addValidator(validator) {
|
178 | this.context.validators.push(validator);
|
179 | return this;
|
180 | }
|
181 | }
|
182 | exports.Predicate = Predicate;
|