Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(develop): added phonenumber type validator to IsPhoneNumber.ts #2557

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 44 additions & 18 deletions src/decorator/string/IsPhoneNumber.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { allPhoneNumberTypes, PhoneNumberType } from '../../utils/phone-number-type';
import { ValidationOptions } from '../ValidationOptions';
import { buildMessage, ValidateBy } from '../common/ValidateBy';
import { parsePhoneNumber, CountryCode } from 'libphonenumber-js/max';

/* Changed import to /max for all metadata provided in the library in order to check phone number type
* since the (default = /min) always returns undefined in the .getType()
* reference https://www.npmjs.com/package/libphonenumber-js
*/
import { parsePhoneNumberFromString, CountryCode } from 'libphonenumber-js/max';

export const IS_PHONE_NUMBER = 'isPhoneNumber';

Expand All @@ -10,26 +16,30 @@ export const IS_PHONE_NUMBER = 'isPhoneNumber';
*
* @param value the potential phone number string to test
* @param region 2 characters uppercase country code (e.g. DE, US, CH) for country specific validation.
* @param acceptedNumbersTypes list of accepted number types (MOBILE, PAGER, etc...) if not provided then accept all valid numbers.
* If text doesn't start with the international calling code (e.g. +41), then you must set this parameter.
*/
export function isPhoneNumber(value: string, region?: CountryCode): boolean {
if (typeof value !== 'string' || value.trim() !== value) {
return false;
}

export function isPhoneNumber(
value: string,
region?: CountryCode,
acceptedNumbersTypes?: Array<PhoneNumberType>
): boolean {
try {
const phoneNumber = parsePhoneNumber(value, region);

/**
* We fail the validation if the user provided a region code
* and it doesn't match with the country code of the parsed number.
**/
if (region && phoneNumber.country !== region) {
return false;
// the list of all phone number types that are the output of .getType() method
let checkedNumberTypes: Array<PhoneNumberType> = allPhoneNumberTypes;

// Checking if accepted types array is passed to override the default
if (acceptedNumbersTypes) {
checkedNumberTypes = acceptedNumbersTypes;
}

return phoneNumber.isValid();
const phoneNum = parsePhoneNumberFromString(value, region);

// number must be valid and is one of the phone types the function accepts (ALL TYPES PROVIDED IN phone-number-types.ts)
const result: boolean = !!phoneNum?.isValid() && !!checkedNumberTypes.some(item => item === phoneNum?.getType());
return result;
} catch (error) {
// logging?
return false;
}
}
Expand All @@ -39,17 +49,33 @@ export function isPhoneNumber(value: string, region?: CountryCode): boolean {
* the intl. calling code, if the calling code wont be provided then the region must be set.
*
* @param region 2 characters uppercase country code (e.g. DE, US, CH) for country specific validation.
* @param acceptedNumbersTypes list of accepted number types (MOBILE, PAGER, etc...) if not provided then accept all valid phone numbers
* If text doesn't start with the international calling code (e.g. +41), then you must set this parameter.
*/
export function IsPhoneNumber(region?: CountryCode, validationOptions?: ValidationOptions): PropertyDecorator {
export function IsPhoneNumber(
region?: CountryCode,
validationOptions?: ValidationOptions,
acceptedNumbersTypes?: Array<PhoneNumberType>
): PropertyDecorator {
// the list of all phone number types that are the output of .getType() method
let checkedNumberTypes: Array<PhoneNumberType> = allPhoneNumberTypes;

// Checking if accepted types array is passed to override the default
if (acceptedNumbersTypes) {
checkedNumberTypes = acceptedNumbersTypes;
}

return ValidateBy(
{
name: IS_PHONE_NUMBER,
constraints: [region],
validator: {
validate: (value, args): boolean => isPhoneNumber(value, args?.constraints[0]),
validate: (value, args): boolean => isPhoneNumber(value, args?.constraints[0], checkedNumberTypes),
defaultMessage: buildMessage(
eachPrefix => eachPrefix + '$property must be a valid phone number',
eachPrefix =>
eachPrefix +
'$property must be a valid phone number and of the following types: ' +
checkedNumberTypes.toString(),
validationOptions
),
},
Expand Down
29 changes: 29 additions & 0 deletions src/utils/phone-number-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
types of all possible return values of the .getType() in the phone number libphonenumber-js/max library
*/
export type PhoneNumberType =
| 'FIXED_LINE_OR_MOBILE'
| 'MOBILE'
| 'FIXED_LINE'
| 'PREMIUM_RATE'
| 'TOLL_FREE'
| 'SHARED_COST'
| 'VOIP'
| 'PERSONAL_NUMBER'
| 'PAGER'
| 'UAN'
| 'VOICEMAIL';

export const allPhoneNumberTypes:Array<PhoneNumberType> = [
'FIXED_LINE_OR_MOBILE',
'MOBILE',
'FIXED_LINE',
'PREMIUM_RATE',
'TOLL_FREE',
'SHARED_COST',
'VOIP',
'PERSONAL_NUMBER',
'PAGER',
'UAN',
'VOICEMAIL',
];