Skip to content

Commit 6c85960

Browse files
committed
feat: added PhoneNumber scalar
1 parent 7ee3b54 commit 6c85960

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

src/PhoneNumber.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { GraphQLScalarType } from 'graphql';
2+
import { GraphQLError } from 'graphql/error';
3+
import { Kind } from 'graphql/language';
4+
5+
const PHONE_NUMBER_REGEX = new RegExp(
6+
/^\+\d{11,15}$/,
7+
);
8+
9+
export default new GraphQLScalarType({
10+
name: 'PhoneNumber',
11+
12+
description:
13+
'A field whose value conforms to the standard E.164 format as specified in: https://en.wikipedia.org/wiki/E.164. Basically this is +17895551234.',
14+
15+
serialize(value) {
16+
if (typeof value !== 'string') {
17+
throw new TypeError(`Value is not string: ${value}`);
18+
}
19+
20+
if (!PHONE_NUMBER_REGEX.test(value)) {
21+
throw new TypeError(`Value is not a valid phone number of the form +17895551234 (10-15 digits): ${value}`);
22+
}
23+
24+
return value;
25+
},
26+
27+
parseValue(value) {
28+
if (typeof value !== 'string') {
29+
throw new TypeError(`Value is not string: ${value}`);
30+
}
31+
32+
if (!PHONE_NUMBER_REGEX.test(value)) {
33+
throw new TypeError(`Value is not a valid phone number of the form +17895551234 (10-15 digits): ${value}`);
34+
}
35+
36+
return value;
37+
},
38+
39+
parseLiteral(ast) {
40+
if (ast.kind !== Kind.STRING) {
41+
throw new GraphQLError(
42+
`Can only validate strings as phone numbers but got a: ${ast.kind}`,
43+
);
44+
}
45+
46+
if (!PHONE_NUMBER_REGEX.test(ast.value)) {
47+
throw new TypeError(`Value is not a valid phone number of the form +17895551234 (10-15 digits): ${ast.value}`);
48+
}
49+
50+
return ast.value;
51+
},
52+
});

src/__tests__/PhoneNumber.test.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/* global describe, test, expect */
2+
3+
import { Kind } from 'graphql/language';
4+
5+
import { PhoneNumber } from '../';
6+
7+
describe('PhoneNumber', () => {
8+
describe('valid', () => {
9+
test('serialize', () => {
10+
expect(PhoneNumber.serialize('+17895551234')).toBe('+17895551234');
11+
});
12+
13+
test('parseValue', () => {
14+
expect(PhoneNumber.parseValue('+17895551234')).toBe('+17895551234');
15+
});
16+
17+
test('parseLiteral', () => {
18+
expect(
19+
PhoneNumber.parseLiteral({ value: '+17895551234', kind: Kind.STRING }),
20+
).toBe('+17895551234');
21+
});
22+
});
23+
24+
describe('invalid', () => {
25+
describe('not a phone number', () => {
26+
test('serialize', () => {
27+
expect(() => PhoneNumber.serialize('this is not a phone number')).toThrow(
28+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
29+
);
30+
});
31+
32+
test('parseValue', () => {
33+
expect(() => PhoneNumber.parseValue('this is not a phone number')).toThrow(
34+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
35+
);
36+
});
37+
38+
test('parseLiteral', () => {
39+
expect(() =>
40+
PhoneNumber.parseLiteral({ value: 'this is not a phone number', kind: Kind.STRING }),
41+
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/);
42+
});
43+
});
44+
45+
describe('not a string', () => {
46+
test('serialize', () => {
47+
expect(() => PhoneNumber.serialize(123)).toThrow(/Value is not string/);
48+
});
49+
50+
test('parseValue', () => {
51+
expect(() => PhoneNumber.parseValue(123)).toThrow(/Value is not string/);
52+
});
53+
54+
test('parseLiteral', () => {
55+
expect(() => PhoneNumber.parseLiteral({ value: 123, kind: Kind.INT })).toThrow(
56+
/Can only validate strings as phone numbers but got a/,
57+
);
58+
});
59+
});
60+
61+
describe('too short', () => {
62+
test('serialize', () => {
63+
expect(() => PhoneNumber.serialize('+1789555123')).toThrow(
64+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
65+
);
66+
});
67+
68+
test('parseValue', () => {
69+
expect(() => PhoneNumber.parseValue('+1789555123')).toThrow(
70+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
71+
);
72+
});
73+
74+
test('parseLiteral', () => {
75+
expect(() =>
76+
PhoneNumber.parseLiteral({ value: '+1789555123', kind: Kind.STRING }),
77+
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/);
78+
});
79+
});
80+
81+
describe('too long', () => {
82+
test('serialize', () => {
83+
expect(() => PhoneNumber.serialize('+1789555123456789')).toThrow(
84+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
85+
);
86+
});
87+
88+
test('parseValue', () => {
89+
expect(() => PhoneNumber.parseValue('+1789555123456789')).toThrow(
90+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
91+
);
92+
});
93+
94+
test('parseLiteral', () => {
95+
expect(() =>
96+
PhoneNumber.parseLiteral({ value: '+1789555123456789', kind: Kind.STRING }),
97+
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/);
98+
});
99+
});
100+
101+
describe('no plus sign', () => {
102+
test('serialize', () => {
103+
expect(() => PhoneNumber.serialize('17895551234')).toThrow(
104+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
105+
);
106+
});
107+
108+
test('parseValue', () => {
109+
expect(() => PhoneNumber.parseValue('17895551234')).toThrow(
110+
/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/,
111+
);
112+
});
113+
114+
test('parseLiteral', () => {
115+
expect(() =>
116+
PhoneNumber.parseLiteral({ value: '17895551234', kind: Kind.STRING }),
117+
).toThrow(/^Value is not a valid phone number of the form \+17895551234 \(10-15 digits\)/);
118+
});
119+
});
120+
});
121+
});

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import NonNegativeFloat from './NonNegativeFloat';
99
import NegativeFloat from './NegativeFloat';
1010
import EmailAddress from './EmailAddress';
1111
import URL from './URL';
12+
import PhoneNumber from './PhoneNumber';
1213

1314
export {
1415
DateTime,
@@ -22,6 +23,7 @@ export {
2223
NegativeFloat,
2324
EmailAddress,
2425
URL,
26+
PhoneNumber,
2527
};
2628

2729
export default {
@@ -35,4 +37,5 @@ export default {
3537
NegativeFloat,
3638
EmailAddress,
3739
URL,
40+
PhoneNumber,
3841
};

0 commit comments

Comments
 (0)