pix-utils-js 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+
2
+ # 💸 pix-utils-js
3
+
4
+ Uma pequena biblioteca que irá te ajudar a lidar com chaves pix
5
+
6
+
7
+
8
+
9
+ ## Instalação
10
+
11
+ Instale pix-utils-js com npm ou yarn
12
+
13
+ ```bash
14
+ npm install pix-utils-js
15
+ yarn add pix-utils-js
16
+ ```
17
+
18
+ ## Documentação
19
+
20
+ #### Identifique uma chave pix
21
+
22
+ ```js
23
+ const { identify } = 'pix-utils-js'
24
+ const { pix, type } = identify({pix: 'test@gmail.com'}) // {pix: 'test@gmail.com', type: 'email'}
25
+ ```
26
+
27
+ | Função | Parametro | Retorno |
28
+ | :---------- | :--------- | :---------------------------------- |
29
+ | `identify` | `input: {pix: string}` | Pix `{ pix: string, type: string }` |
30
+
31
+ #### Validar uma chave pix
32
+
33
+ ```js
34
+ const { validate } = 'pix-utils-js'
35
+ console.log(validate({pix: 'test@gmail.com'})) // true
36
+ console.log(validate({pix: 'test'})) // false
37
+ ```
38
+
39
+ | Função | Parametro | Retorno |
40
+ | :---------- | :--------- | :---------------------------------- |
41
+ | `validate` | `input: {pix: string}` | boolean |
42
+
43
+ #### Normalizar uma chave pix
44
+
45
+ ```js
46
+ const { normalize } = 'pix-utils-js'
47
+ console.log(normalize({pix: '000.000.000-00'})) // {pix: '00000000000', type: 'cpf'}
48
+ console.log(normalize({pix: '00.000.000/0000-00'})) // {pix: '00000000000000', type: 'cnpj'}
49
+ ```
50
+
51
+ | Função | Parametro | Retorno |
52
+ | :---------- | :--------- | :---------------------------------- |
53
+ | `normalize` | `input: {pix: string}` | Pix `{ pix: string, type: string }` |
54
+
55
+
56
+
57
+ ## Rodando os testes
58
+
59
+ Para rodar os testes, rode o seguinte comando
60
+
61
+ ```bash
62
+ npm run test
63
+ ```
64
+
package/index.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export type PixType = "email" | "cpf" | "cnpj" | "random" | "phone"
2
+
3
+ export interface InvalidPix extends Error {
4
+ message: "chave pix invalida."
5
+ }
6
+
7
+ export type Pix = {
8
+ type: PixType,
9
+ pix: string,
10
+ }
11
+
12
+ export interface IdentifyDto {
13
+ pix: string
14
+ }
15
+
16
+ export interface NormalizeDto {
17
+ pix: string
18
+ }
19
+
20
+ export interface ValidateDto {
21
+ type?: PixType,
22
+ pix: string
23
+ }
24
+
25
+ export function identify(input: IdentifyDto): Pix | InvalidPix
26
+ export function normalize(input: NormalizeDto): Pix | InvalidPix
27
+ export function validate(input: ValidateDto): Boolean | InvalidPix
package/index.js ADDED
@@ -0,0 +1,70 @@
1
+ const { Validator } = require('./utils/validator')
2
+
3
+ const validator = new Validator();
4
+
5
+ const validationPixMap = {
6
+ email: validator.isEmail,
7
+ random: validator.isUUID,
8
+ phone: validator.isPhoneNumber,
9
+ cnpj: validator.isCNPJ,
10
+ cpf: validator.isCPF
11
+ };
12
+
13
+
14
+ const validate = (input) => {
15
+ const { pix } = input
16
+ let { type } = input
17
+
18
+ if(!pix) {
19
+ throw new Error("chave pix invalida.")
20
+ }
21
+
22
+ if(!type) {
23
+ try {
24
+ let identifiedPix = identify({ pix })
25
+ type = identifiedPix.type
26
+ }catch {
27
+ return false
28
+ }
29
+ }
30
+
31
+ return validationPixMap[type](pix)
32
+ }
33
+
34
+ const identify = (input) => {
35
+ const { pix } = input
36
+
37
+ if(!pix) {
38
+ throw new Error("chave pix invalida.")
39
+ }
40
+
41
+ for (const type in validationPixMap) {
42
+ if (validationPixMap[type](pix)) {
43
+ return { type, pix };
44
+ }
45
+ }
46
+
47
+ throw new Error("chave pix invalida.")
48
+ }
49
+
50
+ const normalize = (input) => {
51
+ let { pix } = input
52
+
53
+ if(!pix || !validate({ pix})) {
54
+ throw new Error("chave pix invalida.")
55
+ }
56
+
57
+ const { type } = identify({ pix })
58
+
59
+ if(type === 'cpf' || type === 'cnpj') {
60
+ pix = pix.replace(/[^0-9]/g, '')
61
+ }
62
+
63
+ return { pix, type }
64
+ }
65
+
66
+ module.exports = {
67
+ identify,
68
+ validate,
69
+ normalize
70
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "pix-utils-js",
3
+ "version": "1.0.0",
4
+ "author": "Paulo Henrique",
5
+ "description": "Um pacote para fornecer utilidades e validações para chaves pix.",
6
+ "main": "index.js",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/paulohenriquesn/pix-utils-js.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/paulohenriquesn/pix-utils-js/issues"
13
+ },
14
+ "homepage": "https://github.com/paulohenriquesn/pix-utils-js#readme",
15
+ "scripts": {
16
+ "test": "node tests/index.js"
17
+ },
18
+ "keywords": [
19
+ "pix",
20
+ "chave pix"
21
+ ],
22
+ "license": "MIT"
23
+ }
@@ -0,0 +1,107 @@
1
+ class Generator {
2
+ static generateValidPhoneNumber() {
3
+ const dddList = ['11', '21', '31', '41', '51', '61', '71', '81', '91'];
4
+ const selectedDDD = dddList[Math.floor(Math.random() * dddList.length)];
5
+
6
+ const phoneNumber = `${selectedDDD}9${Generator.generateRandomNumber(8)}`;
7
+ return phoneNumber;
8
+ }
9
+
10
+ static generateRandomNumber(length) {
11
+ let randomNumber = '';
12
+ for (let i = 0; i < length; i++) {
13
+ randomNumber += Math.floor(Math.random() * 10);
14
+ }
15
+ return randomNumber;
16
+ }
17
+
18
+ static generateRandomCPF() {
19
+ function randomDigit() {
20
+ return Math.floor(Math.random() * 10);
21
+ }
22
+
23
+ const cpfDigits = [];
24
+ for (let i = 0; i < 9; i++) {
25
+ cpfDigits.push(randomDigit());
26
+ }
27
+
28
+ const firstVerifierDigit = Generator.calculateCPFVerifierDigit(cpfDigits);
29
+ cpfDigits.push(firstVerifierDigit);
30
+
31
+ const secondVerifierDigit = Generator.calculateCPFVerifierDigit(cpfDigits);
32
+ cpfDigits.push(secondVerifierDigit);
33
+
34
+ return cpfDigits.join('');
35
+ }
36
+
37
+ static calculateCPFVerifierDigit(digits) {
38
+ const sum = digits.reduce((acc, digit, index) => {
39
+ const multiplier = digits.length + 1 - index;
40
+ return acc + digit * multiplier;
41
+ }, 0);
42
+
43
+ const remainder = sum % 11;
44
+ return remainder < 2 ? 0 : 11 - remainder;
45
+ }
46
+ static generateValidCNPJ() {
47
+ function randomDigit() {
48
+ return Math.floor(Math.random() * 10);
49
+ }
50
+
51
+ const cnpjBase = [];
52
+ for (let i = 0; i < 12; i++) {
53
+ cnpjBase.push(randomDigit());
54
+ }
55
+
56
+ const verifierDigits = Generator.calculateCNPJVerifierDigits(cnpjBase);
57
+ cnpjBase.push(verifierDigits[0], verifierDigits[1]);
58
+
59
+ const formattedCNPJ = cnpjBase.join('');
60
+
61
+ return formattedCNPJ.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
62
+ }
63
+
64
+ static calculateCNPJVerifierDigits(digits) {
65
+ const multipliers1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
66
+ const multipliers2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3];
67
+
68
+ function calculateDigit(multipliers) {
69
+ const sum = digits.reduce((acc, digit, index) => acc + digit * multipliers[index], 0);
70
+ const remainder = sum % 11;
71
+ return remainder < 2 ? 0 : 11 - remainder;
72
+ }
73
+
74
+ const firstDigit = calculateDigit(multipliers1);
75
+ const secondDigit = calculateDigit(multipliers2);
76
+
77
+ return [firstDigit, secondDigit];
78
+ }
79
+
80
+ static generateRandomUUID() {
81
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
82
+ const r = Math.random() * 16 | 0;
83
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
84
+ return v.toString(16);
85
+ });
86
+ }
87
+
88
+ static generateRandomEmail() {
89
+ const domains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'example.com'];
90
+ const username = Generator.generateRandomString(8);
91
+ const domain = domains[Math.floor(Math.random() * domains.length)];
92
+ return `${username}@${domain}`;
93
+ }
94
+
95
+ static generateRandomString(length) {
96
+ const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
97
+ let randomString = '';
98
+ for (let i = 0; i < length; i++) {
99
+ const randomIndex = Math.floor(Math.random() * characters.length);
100
+ randomString += characters.charAt(randomIndex);
101
+ }
102
+ return randomString;
103
+ }
104
+ }
105
+
106
+
107
+ module.exports = { Generator }
package/tests/index.js ADDED
@@ -0,0 +1,78 @@
1
+ const assert = require('assert');
2
+ const { describe, it } = require('node:test')
3
+ const { identify, normalize, validate } = require('../index')
4
+ const { Generator } = require('./generator')
5
+
6
+ describe('validate', () => {
7
+ it('should returns false if no pix key is provided', (t) => {
8
+ const sut = validate({pix: 'invalid'})
9
+ assert.strictEqual(sut, false);
10
+ });
11
+
12
+ it('should returns true if email key is provided and is valid', (t) => {
13
+ const sut = validate({pix: Generator.generateRandomEmail()})
14
+ assert.strictEqual(sut, true);
15
+ });
16
+
17
+ it('should returns true if phone number key is provided and is valid', (t) => {
18
+ const sut = validate({pix: Generator.generateValidPhoneNumber()})
19
+ assert.strictEqual(sut, true);
20
+ });
21
+
22
+ it('should returns true if random key is provided and is valid', (t) => {
23
+ const sut = validate({pix: Generator.generateRandomUUID()})
24
+ assert.strictEqual(sut, true);
25
+ });
26
+ })
27
+
28
+ describe('identify', () => {
29
+ it('should returns email if email pix is provided', (t) => {
30
+ const sut = identify({ pix: 'test@gmail.com'})
31
+ assert.notStrictEqual(sut, { pix: 'test@gmail.com', type: 'email' });
32
+ });
33
+
34
+ it('should returns cpf if cpf pix is provided', (t) => {
35
+ const cpf = Generator.generateRandomCPF()
36
+ const sut = identify({ pix: cpf})
37
+ assert.notStrictEqual(sut, { pix: cpf, type: 'cpf' });
38
+ });
39
+
40
+
41
+ it('should returns cnpj if cnpj pix is provided', (t) => {
42
+ const cnpj = Generator.generateValidCNPJ()
43
+ const sut = identify({ pix: cnpj})
44
+ assert.notStrictEqual(sut, { pix: cnpj, type: 'cnpj' });
45
+ });
46
+
47
+ it('should returns random if random pix is provided', (t) => {
48
+ const random = Generator.generateRandomUUID()
49
+ const sut = identify({ pix: random })
50
+ assert.notStrictEqual(sut, { pix: random, type: 'random' });
51
+ });
52
+
53
+ it('should returns phone if random pix is provided', (t) => {
54
+ const phone = Generator.generateValidPhoneNumber()
55
+ const sut = identify({ pix: phone })
56
+ assert.notStrictEqual(sut, { pix: phone, type: 'phone' });
57
+ });
58
+
59
+ it('should throws if invalid pix is provided', (t) => {
60
+ let sut;
61
+ try {
62
+ sut = identify({ pix: 'abc' })
63
+ }catch (err) {
64
+ sut = err;
65
+ }
66
+ assert.notStrictEqual(sut, Error);
67
+ });
68
+ })
69
+
70
+ describe("normalize", () => {
71
+ it('should normalize cpf key', (t) => {
72
+ assert.deepEqual(normalize({ pix: "000.000.000-00"}), { pix: '00000000000', type: 'cpf'});
73
+ });
74
+
75
+ it('should normalize cnpj key', (t) => {
76
+ assert.deepEqual(normalize({ pix: "00.000.000/0000-00"}), { pix: '00000000000000', type: 'cnpj'});
77
+ });
78
+ })
@@ -0,0 +1,30 @@
1
+ class Validator {
2
+ isEmail(email) {
3
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
4
+ return emailRegex.test(email)
5
+ }
6
+
7
+ isUUID(uuid) {
8
+ const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/
9
+ return uuidRegex.test(uuid)
10
+ }
11
+
12
+ isPhoneNumber(phoneNumber) {
13
+ const phoneNumberRegex = /^(\d{3}-\d{3}-\d{4}|\d{10}|\(\d{3}\)\s*\d{3}-\d{4}|\d{3}\s\d{3}\s\d{4})$/;
14
+ return phoneNumberRegex.test(phoneNumber)
15
+ }
16
+
17
+ isCPF(cpf) {
18
+ const cpfRegex = /^(\d{3}\.\d{3}\.\d{3}-\d{2}|\d{11})$/;
19
+ return cpfRegex.test(cpf)
20
+ }
21
+
22
+ isCNPJ(cnpj) {
23
+ const cnpjRegex = /^(\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}|\d{14})$/;
24
+ return cnpjRegex.test(cnpj)
25
+ }
26
+ }
27
+
28
+ module.exports = {
29
+ Validator
30
+ }