Skip to content

Commit

Permalink
feat: add validation to phone number by format
Browse files Browse the repository at this point in the history
* feat(telephones): verify phone numbers

* test(telephones): check valid and invalid cases

Use property-based testing with fast-check

* docs(telephones): update README.md

Add examples for new functions

* test(telephones): verify unassigned phone numbers

The SIGET did assign yet phones outside
the range of 2000-0000 to 2999-9999 and 6000-0000 to 7999-9999

SEE https://www.siget.gob.sv/numeros-fijos/ https://www.siget.gob.sv/numeros-moviles/
  • Loading branch information
leosuncin committed Aug 6, 2020
1 parent 3da05a6 commit 6da4486
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 0 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
[![PRs Welcome][prs-badge]][prs]
[![Commitizen friendly][cz-badge]][cz]
[![MIT License][license-badge]][license]

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-)

<!-- ALL-CONTRIBUTORS-BADGE:END -->

[![Watch on GitHub][github-watch-badge]][github-watch]
Expand Down Expand Up @@ -57,6 +60,48 @@ isNIT(fakeNIT); // false
isNIT(validNIT); // true
```

- #### isMobilePhoneNumber

```ts
import { isMobilePhoneNumber } from 'sivar-utils';

const str = 'test';
const fakeMobilePhone = '9999-9999';
const validMobilePhone = '7071-1244'; // DISCLAIMER: taken from Google

isMobilePhoneNumber(str); // false
isMobilePhoneNumber(fakeMobilePhone); // false
isMobilePhoneNumber(validMobilePhone); // true
```

- #### isResidentialPhoneNumber

```ts
import { isResidentialPhoneNumber } from 'sivar-utils';

const str = 'test';
const fakeResidentialPhone = '5555-5555';
const validResidentialPhone = '2244-4777'; // DISCLAIMER: taken from Google

isResidentialPhoneNumber(str); // false
isResidentialPhoneNumber(fakeResidentialPhone); // false
isResidentialPhoneNumber(validResidentialPhone); // true
```

- #### isPhoneNumber

```ts
import { isPhoneNumber } from 'sivar-utils';

const str = 'test';
const fakePhone = '1234-5678';
const validPhone = '2591-3000'; /* or '7725-4747' */ // DISCLAIMER: taken from Google

isPhoneNumber(str); // false
isPhoneNumber(fakePhone); // false
isPhoneNumber(validPhone); // true
```

## Contributing

### How to contribute?
Expand Down Expand Up @@ -91,6 +136,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
Expand Down
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"eslint-plugin-import": "^2.18.0",
"eslint-plugin-jsdoc": "^22.1.0",
"eslint-plugin-prettier": "^3.1.0",
"fast-check": "^1.25.1",
"gh-pages": "^2.2.0",
"husky": "^4.2.3",
"jest": "^25.2.4",
Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
export { isDUI, isNIT } from './lib/documents';
export { isMunicipalityCode } from './lib/municipalities';
export {
isMobilePhoneNumber,
isResidentialPhoneNumber,
isPhoneNumber,
} from './lib/telephones';
90 changes: 90 additions & 0 deletions src/lib/__tests__/telephones.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import fc from 'fast-check';
import {
isMobilePhoneNumber,
isResidentialPhoneNumber,
isPhoneNumber,
} from '../telephones';

/**
* Mask a number with phone format
*
* @memberof helpers
* @param {number} number A 8 digits number
* @returns {string} A phone number formatted
*/
const maskPhoneNumber = (number: number): string =>
number.toString().replace(/^(\d{4})(\d{4})$/, '$1-$2');
/**
* Generate mobile phone numbers from 6000-0000 to 7999-9999
*
* @returns {() => fc.Arbitrary<string>} A random mobile phone number
*/
const mobilePhone: () => fc.Arbitrary<string> = () =>
fc.integer(60000000, 79999999).map(maskPhoneNumber);
/**
* Generate residential phone number from 2000-0000 to 2999-9999
*
* @returns {() => fc.Arbitrary<string>} A random residential phone number
*/
const residentialPhone: () => fc.Arbitrary<string> = () =>
fc.integer(20000000, 29999999).map(maskPhoneNumber);
/**
* Generate not assigned phone numbers
*
* @returns {() => fc.Arbitrary<string>} A random residential phone number
*/
const unassignedPhone: () => fc.Arbitrary<string> = () =>
fc
.oneof(fc.integer(10000000, 19999999), fc.integer(80000000, 99999999))
.map(maskPhoneNumber);

describe('telephones', () => {
describe('isMobilePhone', () => {
test('should verify mobile phone numbers', () =>
fc.assert(
fc.property(mobilePhone(), (phone) => isMobilePhoneNumber(phone))
));

test('should returns false for everything else', () =>
fc.assert(
fc.property(
fc.oneof(fc.anything(), fc.string(9)),
(phone) => !isMobilePhoneNumber(phone as any)
)
));
});

describe('isResidentialPhone', () => {
test('should verify residential phone numbers', () =>
fc.assert(
fc.property(residentialPhone(), (phone) =>
isResidentialPhoneNumber(phone)
)
));

test('should returns false for everything else', () =>
fc.assert(
fc.property(
fc.oneof(fc.anything(), fc.string(9)),
(phone) => !isResidentialPhoneNumber(phone as any)
)
));
});

describe('isPhoneNumber', () => {
test('should verify phone numbers', () =>
fc.assert(
fc.property(fc.oneof(mobilePhone(), residentialPhone()), (phone) =>
isPhoneNumber(phone)
)
));

test('should returns false for everything else', () =>
fc.assert(
fc.property(
fc.oneof(unassignedPhone()),
(phone) => !isPhoneNumber(phone)
)
));
});
});
42 changes: 42 additions & 0 deletions src/lib/telephones.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Beginning with 6 or 7 follow by three digits, then a dash and ends with four digits only
*/
const mobilePhoneRegExP = /^[67]\d{3}-\d{4}$/;
/**
* Beginning with 2 follow by three digits, then a dash and ends with four digits only
*/
const residentialPhoneRegExP = /^2\d{3}-\d{4}$/;

/**
* Verifies that given string number is a mobile number
*
* @param {string} phone A string phone number with a dash included
* @returns {boolean} Is a valid mobile phone number
*/
export function isMobilePhoneNumber(phone: string): boolean {
if (typeof phone !== 'string') return false;

return mobilePhoneRegExP.test(phone);
}

/**
* Verifies that given string number is a residential number
*
* @param {string} phone A string phone number with a dash included
* @returns {boolean} Is a valid residential phone number
*/
export function isResidentialPhoneNumber(phone: string): boolean {
if (typeof phone !== 'string') return false;

return residentialPhoneRegExP.test(phone);
}

/**
* Verifies that given string number is a phone number
*
* @param {string} phone A string phone number with a dash included
* @returns {boolean} Is a valid phone number
*/
export function isPhoneNumber(phone: string): boolean {
return isMobilePhoneNumber(phone) || isResidentialPhoneNumber(phone);
}

0 comments on commit 6da4486

Please sign in to comment.