Skip to content

Commit c53cb35

Browse files
authored
feat: support tel type validator (#21)
* feat: support tel type validator * feat: support tel type validator
1 parent f2feb39 commit c53cb35

File tree

7 files changed

+183
-1
lines changed

7 files changed

+183
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Indicates the `type` of validator to use. Recognised type values are:
183183
- `url`: Must be of type `url`.
184184
- `hex`: Must be of type `hex`.
185185
- `email`: Must be of type `email`.
186+
- `tel`: Must be of type `tel`.
186187
- `any`: Can be any type.
187188

188189
#### Required

src/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type RuleType =
1515
| 'url'
1616
| 'hex'
1717
| 'email'
18+
| 'tel'
1819
| 'pattern'
1920
| 'any';
2021

@@ -146,6 +147,7 @@ export interface ValidateMessages {
146147
float?: ValidateMessage<[FullField, Type]>;
147148
regexp?: ValidateMessage<[FullField, Type]>;
148149
email?: ValidateMessage<[FullField, Type]>;
150+
tel?: ValidateMessage<[FullField, Type]>;
149151
url?: ValidateMessage<[FullField, Type]>;
150152
hex?: ValidateMessage<[FullField, Type]>;
151153
};

src/messages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export function newMessages(): InternalValidateMessages {
2323
float: '%s is not a %s',
2424
regexp: '%s is not a valid %s',
2525
email: '%s is not a valid %s',
26+
tel: '%s is not a valid %s',
2627
url: '%s is not a valid %s',
2728
hex: '%s is not a valid %s',
2829
},

src/rule/type.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ const pattern = {
1212
// '^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$',
1313
// 'i',
1414
// ),
15+
/**
16+
* Phone number regex, support country code, brackets, spaces, and dashes (or non-breaking hyphen \u2011).
17+
* @see https://regexr.com/3c53v
18+
* @see https://ihateregex.io/expr/phone/
19+
* @see https://developers.google.com/style/phone-numbers using non-breaking hyphen \u2011
20+
*/
21+
tel: /^(\+[0-9]{1,3}[-\s\u2011]?)?(\([0-9]{1,4}\)[-\s\u2011]?)?([0-9]+[-\s\u2011]?)*[0-9]+$/,
1522
hex: /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i,
1623
};
1724

@@ -58,6 +65,9 @@ const types = {
5865
email(value: Value) {
5966
return typeof value === 'string' && value.length <= 320 && !!value.match(pattern.email);
6067
},
68+
tel(value: Value) {
69+
return typeof value === 'string' && value.length <= 32 && !!value.match(pattern.tel);
70+
},
6171
url(value: Value) {
6272
return typeof value === 'string' && value.length <= 2048 && !!value.match(getUrlRegex());
6373
},
@@ -79,6 +89,7 @@ const type: ExecuteRule = (rule, value, source, errors, options) => {
7989
'object',
8090
'method',
8191
'email',
92+
'tel',
8293
'number',
8394
'date',
8495
'url',

src/util.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ function isNativeStringType(type: string) {
9191
type === 'hex' ||
9292
type === 'email' ||
9393
type === 'date' ||
94-
type === 'pattern'
94+
type === 'pattern' ||
95+
type === 'tel'
9596
);
9697
}
9798

src/validator/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default {
3030
url: type,
3131
hex: type,
3232
email: type,
33+
tel: type,
3334
required,
3435
any,
3536
};

tests/tel.spec.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import Schema from '../src';
2+
3+
describe('tel', () => {
4+
it('works for empty string', done => {
5+
new Schema({
6+
v: {
7+
type: 'tel',
8+
},
9+
}).validate(
10+
{
11+
v: '',
12+
},
13+
errors => {
14+
expect(errors).toBe(null);
15+
done();
16+
},
17+
);
18+
});
19+
20+
it('works for china mobile phone number', done => {
21+
new Schema({
22+
v: {
23+
type: 'tel',
24+
},
25+
}).validate(
26+
{
27+
v: '13156451303',
28+
},
29+
errors => {
30+
expect(errors).toBe(null);
31+
done();
32+
},
33+
);
34+
});
35+
36+
it('works for china mobile phone number with country code', done => {
37+
new Schema({
38+
v: {
39+
type: 'tel',
40+
},
41+
}).validate(
42+
{
43+
v: '+8613156451303',
44+
},
45+
errors => {
46+
expect(errors).toBe(null);
47+
done();
48+
},
49+
);
50+
});
51+
52+
it('works for china mobile phone number with spaces', done => {
53+
new Schema({
54+
v: {
55+
type: 'tel',
56+
},
57+
}).validate(
58+
{
59+
v: '+86 131 5645 1303',
60+
},
61+
errors => {
62+
expect(errors).toBe(null);
63+
done();
64+
},
65+
);
66+
});
67+
68+
it('works for us phone number with dashes', done => {
69+
new Schema({
70+
v: {
71+
type: 'tel',
72+
},
73+
}).validate(
74+
{
75+
v: '415-555-0132',
76+
},
77+
errors => {
78+
expect(errors).toBe(null);
79+
done();
80+
},
81+
);
82+
});
83+
84+
it('works for us phone number with brackets, dashes, and spaces', done => {
85+
new Schema({
86+
v: {
87+
type: 'tel',
88+
},
89+
}).validate(
90+
{
91+
v: '(123) 456-7890',
92+
},
93+
errors => {
94+
expect(errors).toBe(null);
95+
done();
96+
},
97+
);
98+
});
99+
100+
it('works for us phone number with nonbreaking hyphen', done => {
101+
new Schema({
102+
v: {
103+
type: 'tel',
104+
},
105+
}).validate(
106+
{
107+
v: '415‑555‑0132',
108+
},
109+
errors => {
110+
expect(errors).toBe(null);
111+
done();
112+
},
113+
);
114+
});
115+
116+
it('forbid multiple spaces in a row', done => {
117+
new Schema({
118+
v: {
119+
type: 'tel',
120+
},
121+
}).validate(
122+
{
123+
v: '123 456',
124+
},
125+
errors => {
126+
expect(errors[0].message).toBe('v is not a valid tel');
127+
done();
128+
},
129+
);
130+
});
131+
132+
it('forbid multiple dashes in a row', done => {
133+
new Schema({
134+
v: {
135+
type: 'tel',
136+
},
137+
}).validate(
138+
{
139+
v: '123---456',
140+
},
141+
errors => {
142+
expect(errors[0].message).toBe('v is not a valid tel');
143+
done();
144+
},
145+
);
146+
});
147+
148+
it('works for required empty string', done => {
149+
new Schema({
150+
v: {
151+
type: 'tel',
152+
required: true,
153+
},
154+
}).validate(
155+
{
156+
v: '',
157+
},
158+
errors => {
159+
expect(errors.length).toBe(1);
160+
expect(errors[0].message).toBe('v is required');
161+
done();
162+
},
163+
);
164+
});
165+
});

0 commit comments

Comments
 (0)