Skip to content

Commit 4d10408

Browse files
committed
add numberPatter rules
1 parent aa06bb6 commit 4d10408

10 files changed

+195
-57
lines changed

src/Validator.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
minValue,
3333
maxValue,
3434
rangeValue,
35+
numberPattern,
3536
} from './utils/validators';
3637
import * as util from 'util';
3738

@@ -412,4 +413,19 @@ export default class Validator {
412413
rangeValue(min: number, max: number, message: string = Validator.messages.rangeValueMessage) {
413414
this.rule(util.format(message, min, max), (eva) => rangeValue(min, max, eva));
414415
}
416+
417+
/**
418+
* Validates that the string matches the pattern, replacing the x's with numbers <br/>
419+
* <b>Example:</b> For the pattern +xx (xxx) xxx-xx-xx, the following Strings are valid:
420+
* <ul>
421+
* <li>+12 (345) 678-90-12</li>
422+
* <li>+xx (345) 678-90-12</li>
423+
* <li>+xx (xxx) xxx-xx-xx</li>
424+
* <ul/>
425+
* @param pattern string with the pattern
426+
* @param message Error message
427+
*/
428+
numberPattern(pattern: string, message: string = Validator.messages.numberPatternMessage) {
429+
this.rule(util.format(message, pattern), (eva) => numberPattern(pattern, eva));
430+
}
415431
}

src/ValidatorBuilder.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
minValue,
3131
maxValue,
3232
rangeValue,
33+
numberPattern,
3334
} from './utils/validators';
3435
import * as util from 'util';
3536

@@ -369,6 +370,22 @@ export default class ValidatorBuilder {
369370
return this.rule(util.format(message, min, max), (eva) => rangeValue(min, max, eva));
370371
}
371372

373+
/**
374+
* Validates that the string matches the pattern, replacing the x's with numbers <br/>
375+
* <b>Example:</b> For the pattern +xx (xxx) xxx-xx-xx, the following Strings are valid:
376+
* <ul>
377+
* <li>+12 (345) 678-90-12</li>
378+
* <li>+xx (345) 678-90-12</li>
379+
* <li>+xx (xxx) xxx-xx-xx</li>
380+
* <ul/>
381+
* @param pattern string with the pattern
382+
* @param message Error message
383+
* @return ValidatorBuilder
384+
*/
385+
numberPattern(pattern: string, message: string = Validator.messages.numberPatternMessage): ValidatorBuilder {
386+
return this.rule(util.format(message, pattern), (eva) => numberPattern(pattern, eva));
387+
}
388+
372389
/**
373390
* Build the Validator
374391
* @return Validator

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import Messages from './messages/Messages';
44
import messagesEs from './messages/MessagesEs';
55
import messagesEn from './messages/MessagesEn';
66
import InvalidEvaluationError from './exceptions/InvalidEvaluationError';
7-
import * as regularExpressions from './utils/regularExpressions';
7+
import RE from './utils/regularExpressions';
88

9-
export { Validator, ValidatorBuilder, Messages, messagesEs, messagesEn, InvalidEvaluationError, regularExpressions };
9+
export { Validator, ValidatorBuilder, Messages, messagesEs, messagesEn, InvalidEvaluationError, RE };

src/messages/Messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ export default interface Messages {
2929
minValueMessage: string;
3030
maxValueMessage: string;
3131
rangeValueMessage: string;
32+
numberPatternMessage: string;
3233
}

src/messages/MessagesEn.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const messageEn: Messages = {
3131
minValueMessage: 'The value cannot be less than %s',
3232
maxValueMessage: 'The value cannot be greater than %s',
3333
rangeValueMessage: 'The value must be between %s and %s',
34+
numberPatternMessage: 'Does not match pattern %s',
3435
};
3536

3637
export default messageEn;

src/messages/MessagesEs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const messageEs: Messages = {
3131
minValueMessage: 'El valor no puede ser menor a %s',
3232
maxValueMessage: 'El valor no puede ser mayor a %s',
3333
rangeValueMessage: 'El valor debe estar entre %s y %s',
34+
numberPatternMessage: 'No coincide con el patrón %s',
3435
};
3536

3637
export default messageEs;

src/utils/regularExpressions.ts

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
export const EMAIL =
2-
"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$";
3-
export const DECIMAL = '^\\-?\\d*\\.?\\d+?$';
4-
export const LINK = '^((https://)|(www.)|(http://))+([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$';
5-
export const WWW_LINK = '^www.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$';
6-
export const HTTP_LINK = '^http://.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$';
7-
export const HTTPS_LINK = '^https://.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$';
8-
export const IP =
9-
'^((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))$';
10-
export const IPV4 =
11-
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$';
12-
export const IPV6 =
13-
'^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$';
14-
export const NAME = '^[a-zA-Z]+(\\s?[a-zA-Z])*$';
15-
export const NUMBER = '^\\d+$';
16-
export const ALPHABET = '^[a-zA-Z]+$';
17-
export const ALPHA_NUMERIC = '^[a-zA-Z0-9]+$';
18-
export const TIME =
19-
'^(^(([0-1]?\\d)|(2[0-3])):([0-5][0-9])(:?[0-5][0-9])?$)|(^((0?[1-9])|(1[0-2])):([0-5][0-9])(:[0-5][0-9])?\\s?([aA]|[pP])[mM]$)$';
20-
export const TIME12 = '^((0?[1-9])|(1[0-2])):([0-5][0-9])(:[0-5][0-9])?\\s?([aA]|[pP])[mM]$';
21-
export const TIME24 = '^(([0-1]?\\d)|(2[0-3])):([0-5][0-9])(:?[0-5][0-9])?$';
1+
export default Object.freeze({
2+
EMAIL:
3+
"^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$",
4+
DECIMAL: '^\\-?\\d*\\.?\\d+?$',
5+
LINK: '^((https://)|(www.)|(http://))+([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$',
6+
WWW_LINK: '^www.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$',
7+
HTTP_LINK: '^http://.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$',
8+
HTTPS_LINK: '^https://.([a-zA-Z0-9@:%._+~#=]{2,63})+\\.([a-z]{2,6}\\b)+(.)*$',
9+
IP: '^((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))$',
10+
IPV4: '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$',
11+
IPV6: '^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$',
12+
NAME: '^[a-zA-Z]+(\\s?[a-zA-Z])*$',
13+
NUMBER: '^\\d+$',
14+
ALPHABET: '^[a-zA-Z]+$',
15+
ALPHA_NUMERIC: '^[a-zA-Z0-9]+$',
16+
TIME: '^(^(([0-1]?\\d)|(2[0-3])):([0-5][0-9])(:?[0-5][0-9])?$)|(^((0?[1-9])|(1[0-2])):([0-5][0-9])(:[0-5][0-9])?\\s?([aA]|[pP])[mM]$)$',
17+
TIME12: '^((0?[1-9])|(1[0-2])):([0-5][0-9])(:[0-5][0-9])?\\s?([aA]|[pP])[mM]$',
18+
TIME24: '^(([0-1]?\\d)|(2[0-3])):([0-5][0-9])(:?[0-5][0-9])?$',
19+
});

src/utils/validators.ts

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,4 @@
1-
import {
2-
DECIMAL,
3-
EMAIL,
4-
LINK,
5-
WWW_LINK,
6-
HTTP_LINK,
7-
HTTPS_LINK,
8-
IP,
9-
IPV4,
10-
IPV6,
11-
NAME,
12-
TIME,
13-
TIME12,
14-
TIME24,
15-
NUMBER,
16-
ALPHABET,
17-
ALPHA_NUMERIC,
18-
} from './regularExpressions';
1+
import RE from './regularExpressions';
192

203
/**
214
* Validates that the string is different from null and empty
@@ -89,7 +72,7 @@ export function re(regExp: string, evaluate?: string | null): boolean {
8972
*/
9073
export function email(evaluate?: string | null): boolean {
9174
if (!required(evaluate)) return false;
92-
return re(EMAIL, evaluate);
75+
return re(RE.EMAIL, evaluate);
9376
}
9477

9578
/**
@@ -100,7 +83,7 @@ export function email(evaluate?: string | null): boolean {
10083
*/
10184
export function number(evaluate?: string | null): boolean {
10285
if (!required(evaluate)) return false;
103-
return re(DECIMAL, evaluate);
86+
return re(RE.DECIMAL, evaluate);
10487
}
10588

10689
/**
@@ -110,7 +93,7 @@ export function number(evaluate?: string | null): boolean {
11093
*/
11194
export function link(evaluate?: string | null): boolean {
11295
if (!required(evaluate)) return false;
113-
return re(LINK, evaluate);
96+
return re(RE.LINK, evaluate);
11497
}
11598

11699
/**
@@ -120,7 +103,7 @@ export function link(evaluate?: string | null): boolean {
120103
*/
121104
export function wwwLink(evaluate?: string | null): boolean {
122105
if (!required(evaluate)) return false;
123-
return re(WWW_LINK, evaluate);
106+
return re(RE.WWW_LINK, evaluate);
124107
}
125108

126109
/**
@@ -130,7 +113,7 @@ export function wwwLink(evaluate?: string | null): boolean {
130113
*/
131114
export function httpLink(evaluate?: string | null): boolean {
132115
if (!required(evaluate)) return false;
133-
return re(HTTP_LINK, evaluate);
116+
return re(RE.HTTP_LINK, evaluate);
134117
}
135118

136119
/**
@@ -140,7 +123,7 @@ export function httpLink(evaluate?: string | null): boolean {
140123
*/
141124
export function httpsLink(evaluate?: string | null): boolean {
142125
if (!required(evaluate)) return false;
143-
return re(HTTPS_LINK, evaluate);
126+
return re(RE.HTTPS_LINK, evaluate);
144127
}
145128

146129
/**
@@ -150,7 +133,7 @@ export function httpsLink(evaluate?: string | null): boolean {
150133
*/
151134
export function ip(evaluate?: string | null): boolean {
152135
if (!required(evaluate)) return false;
153-
return re(IP, evaluate);
136+
return re(RE.IP, evaluate);
154137
}
155138

156139
/**
@@ -160,7 +143,7 @@ export function ip(evaluate?: string | null): boolean {
160143
*/
161144
export function ipv4(evaluate?: string | null): boolean {
162145
if (!required(evaluate)) return false;
163-
return re(IPV4, evaluate);
146+
return re(RE.IPV4, evaluate);
164147
}
165148

166149
/**
@@ -170,7 +153,7 @@ export function ipv4(evaluate?: string | null): boolean {
170153
*/
171154
export function ipv6(evaluate?: string | null): boolean {
172155
if (!required(evaluate)) return false;
173-
return re(IPV6, evaluate);
156+
return re(RE.IPV6, evaluate);
174157
}
175158

176159
/**
@@ -188,7 +171,7 @@ export function ipv6(evaluate?: string | null): boolean {
188171
*/
189172
export function name(evaluate?: string | null): boolean {
190173
if (!required(evaluate)) return false;
191-
return re(NAME, evaluate);
174+
return re(RE.NAME, evaluate);
192175
}
193176

194177
/**
@@ -198,7 +181,7 @@ export function name(evaluate?: string | null): boolean {
198181
*/
199182
export function time(evaluate?: string | null): boolean {
200183
if (!required(evaluate)) return false;
201-
return re(TIME, evaluate);
184+
return re(RE.TIME, evaluate);
202185
}
203186

204187
/**
@@ -208,7 +191,7 @@ export function time(evaluate?: string | null): boolean {
208191
*/
209192
export function time12(evaluate?: string | null): boolean {
210193
if (!required(evaluate)) return false;
211-
return re(TIME12, evaluate);
194+
return re(RE.TIME12, evaluate);
212195
}
213196

214197
/**
@@ -218,7 +201,7 @@ export function time12(evaluate?: string | null): boolean {
218201
*/
219202
export function time24(evaluate?: string | null): boolean {
220203
if (!required(evaluate)) return false;
221-
return re(TIME24, evaluate);
204+
return re(RE.TIME24, evaluate);
222205
}
223206

224207
/**
@@ -227,7 +210,7 @@ export function time24(evaluate?: string | null): boolean {
227210
*/
228211
export function onlyNumbers(evaluate?: string | null): boolean {
229212
if (!required(evaluate)) return false;
230-
return re(NUMBER, evaluate);
213+
return re(RE.NUMBER, evaluate);
231214
}
232215

233216
/**
@@ -238,7 +221,7 @@ export function onlyNumbers(evaluate?: string | null): boolean {
238221
*/
239222
export function onlyLetters(evaluate?: string | null): boolean {
240223
if (!required(evaluate)) return false;
241-
return re(ALPHABET, evaluate);
224+
return re(RE.ALPHABET, evaluate);
242225
}
243226

244227
/**
@@ -249,7 +232,7 @@ export function onlyLetters(evaluate?: string | null): boolean {
249232
*/
250233
export function onlyAlphanumeric(evaluate?: string | null): boolean {
251234
if (!required(evaluate)) return false;
252-
return re(ALPHA_NUMERIC, evaluate);
235+
return re(RE.ALPHA_NUMERIC, evaluate);
253236
}
254237

255238
/**
@@ -336,3 +319,30 @@ export function rangeValue(min: number, max: number, evaluate?: string | null):
336319
if (!evaluate || !number(evaluate)) return false;
337320
return +evaluate >= min && +evaluate <= max;
338321
}
322+
323+
/**
324+
* Validates that the string matches the pattern, replacing the x's with numbers <br/>
325+
* <b>Example:</b> For the pattern +xx (xxx) xxx-xx-xx, the following Strings are valid:
326+
* <ul>
327+
* <li>+12 (345) 678-90-12</li>
328+
* <li>+xx (345) 678-90-12</li>
329+
* <li>+xx (xxx) xxx-xx-xx</li>
330+
* <ul/>
331+
* @param pattern String with the pattern
332+
* @param evaluate String to evaluate
333+
* @return true if it meets the condition
334+
*/
335+
export function numberPattern(pattern: string, evaluate?: string | null): boolean {
336+
if (!evaluate) return false;
337+
if (evaluate.length !== pattern.length) return false;
338+
for (let i = 0; i < pattern.split('').length; i++) {
339+
const patterChar = pattern[i];
340+
const evaluateChar = evaluate[i];
341+
if (patterChar === 'x' || patterChar === 'X') {
342+
if (!onlyNumbers(evaluateChar)) if (patterChar !== evaluateChar) return false;
343+
} else {
344+
if (patterChar !== evaluateChar) return false;
345+
}
346+
}
347+
return true;
348+
}

test/rules/numberPattern.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { describe, expect, test } from '@jest/globals';
2+
import { Validator, ValidatorBuilder } from '../../src';
3+
import * as util from 'util';
4+
5+
describe('numberPattern test', () => {
6+
const CONDITION = '+xx (xxx) xxx-xx-xx';
7+
const NOT_PERMIT = [
8+
null,
9+
undefined,
10+
'',
11+
'example',
12+
'128',
13+
'+58 (412) 756-41-79 ',
14+
' +58 (412) 756-41-79',
15+
'+a8 (412) 756-41-79',
16+
];
17+
const PERMIT = ['+58 (412) 756-41-79', '+xx (xxx) xxx-xx-xx'];
18+
const MESSAGE = util.format(Validator.messages.numberPatternMessage, CONDITION);
19+
20+
let validator: Validator, builder: Validator;
21+
22+
beforeEach(() => {
23+
validator = new Validator();
24+
validator.numberPattern(CONDITION);
25+
26+
builder = new ValidatorBuilder().numberPattern(CONDITION).build();
27+
});
28+
29+
test('notPermit', () => {
30+
const result = NOT_PERMIT.every((eva) => !validator.isValid(eva));
31+
expect(result).toBe(true);
32+
});
33+
34+
test('Permit', () => {
35+
const result = PERMIT.every((eva) => validator.isValid(eva));
36+
expect(result).toBe(true);
37+
});
38+
39+
test('notPermit_builder', () => {
40+
const result = NOT_PERMIT.every((eva) => !builder.isValid(eva));
41+
expect(result).toBe(true);
42+
});
43+
44+
test('Permit_builder', () => {
45+
const result = PERMIT.every((eva) => builder.isValid(eva));
46+
expect(result).toBe(true);
47+
});
48+
49+
test('verifyCallback', () => {
50+
const onInvalidEvaluation = jest.fn((message: string) => expect(MESSAGE).toBe(message));
51+
validator.onInvalidEvaluation = onInvalidEvaluation;
52+
validator.isValid();
53+
expect(onInvalidEvaluation).toHaveBeenCalled();
54+
});
55+
56+
test('verifyCallback_builder', () => {
57+
const onInvalidEvaluation = jest.fn((message: string) => expect(MESSAGE).toBe(message));
58+
builder.onInvalidEvaluation = onInvalidEvaluation;
59+
builder.isValid();
60+
expect(onInvalidEvaluation).toHaveBeenCalled();
61+
});
62+
63+
test('throwInvalidEvaluationError', () => {
64+
expect(() => validator.validOrFail('')).toThrowError(MESSAGE);
65+
});
66+
67+
test('throwInvalidEvaluationError_builder', () => {
68+
expect(() => builder.validOrFail('')).toThrowError(MESSAGE);
69+
});
70+
});

0 commit comments

Comments
 (0)