Skip to content

Commit 576b738

Browse files
authored
Merge pull request #8 from Sysvale/feature/cns-validator
feat: adiciona validação de cns
2 parents 40df2ed + fe67a69 commit 576b738

6 files changed

Lines changed: 250 additions & 1 deletion

File tree

docs/utils/cnsValidator.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# CnsValidator
2+
3+
Utilitário para validar CNS com e sem máscara.
4+
5+
## Instalação e Importação
6+
7+
```typescript
8+
import { cnsValidator } from '@sysvale/foundry';
9+
```
10+
11+
## Função
12+
13+
### `cnsValidator()`
14+
15+
Valida CNS com e sem máscara, indicando se os mesmos são válidos.
16+
17+
#### Sintaxes
18+
19+
```typescript
20+
cnsValidator(value: string): boolean
21+
```
22+
23+
#### Parâmetros
24+
25+
**Assinatura 1:**
26+
27+
- **`value`** (`string`): CNS (com ou sem máscara) a ser validado
28+
29+
<br />
30+
31+
#### Retorno
32+
33+
`boolean` - Resultado da validação, `true` para CNS válido e `false` para inválido
34+
35+
<br />
36+
37+
#### Exemplos
38+
39+
**Usando CNS com máscara:**
40+
41+
```typescript
42+
cnsValidator('728 1376 2535 3587'); // → true
43+
44+
cnsValidator('111 1111 1111 1111'); // → false
45+
```
46+
47+
<br />
48+
49+
**Usando CNS sem máscara:**
50+
51+
```typescript
52+
cnsValidator('728137625353587'); // → true
53+
54+
cnsValidator('111111111111111'); // → false
55+
```
56+
57+
<br />
58+
59+
#### Tratamento de Erros
60+
61+
A função lança um erro quando os parâmetros obrigatórios não são fornecidos:
62+
63+
```typescript
64+
// ❌ Erro: tipagem do parâmetro é inválida
65+
cnsValidator(728137625353587);
66+
// → Error: O tipo do parâmetro passado é inválido.
67+
68+
// ✅ Correto
69+
cnsValidator('728137625353587');
70+
```
71+
72+
## Notas
73+
74+
- A função é **type-safe**

docs/utils/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@ Função para sanitizar dados de formulário e aplicar transformações antes de
2323
Função para validar CPFs com e sem máscara.
2424

2525
- [Documentação](./cpfValidator.md)
26+
27+
### cnsValidator()
28+
29+
Função para validar CNS com e sem máscara.
30+
31+
- [Documentação](./cnsValidator.md)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sysvale/foundry",
3-
"version": "1.6.0",
3+
"version": "1.7.0",
44
"description": "A forge for composables, helpers, and front-end utilities.",
55
"type": "module",
66
"main": "./dist/foundry.cjs.js",

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './utils/pluralize';
22
export * from './utils/commaline';
33
export * from './utils/sanitizeForm';
44
export * from './utils/cpfValidator';
5+
export * from './utils/cnsValidator';
56
export { maskCpf, removeCpfMask } from './formatters/cpf';
67
export { maskCns, removeCnsMask } from './formatters/cns';
78
export { maskPhone, removePhoneMask } from './formatters/phone';

src/utils/cnsValidator.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
function checkCnsValue(value: string) {
2+
let pis;
3+
let rest;
4+
let sum;
5+
6+
pis = value.substring(0, 15);
7+
8+
if (pis === '') {
9+
return false;
10+
}
11+
12+
if (
13+
value.substring(0, 1) !== '7' &&
14+
value.substring(0, 1) !== '8' &&
15+
value.substring(0, 1) !== '9'
16+
) {
17+
return false;
18+
}
19+
20+
sum =
21+
parseInt(pis.substring(0, 1), 10) * 15 +
22+
parseInt(pis.substring(1, 2), 10) * 14 +
23+
parseInt(pis.substring(2, 3), 10) * 13 +
24+
parseInt(pis.substring(3, 4), 10) * 12 +
25+
parseInt(pis.substring(4, 5), 10) * 11 +
26+
parseInt(pis.substring(5, 6), 10) * 10 +
27+
parseInt(pis.substring(6, 7), 10) * 9 +
28+
parseInt(pis.substring(7, 8), 10) * 8 +
29+
parseInt(pis.substring(8, 9), 10) * 7 +
30+
parseInt(pis.substring(9, 10), 10) * 6 +
31+
parseInt(pis.substring(10, 11), 10) * 5 +
32+
parseInt(pis.substring(11, 12), 10) * 4 +
33+
parseInt(pis.substring(12, 13), 10) * 3 +
34+
parseInt(pis.substring(13, 14), 10) * 2 +
35+
parseInt(pis.substring(14, 15), 10) * 1;
36+
37+
rest = sum % 11;
38+
39+
if (!rest) {
40+
return true;
41+
}
42+
43+
return false;
44+
}
45+
46+
function checkCnsFirstElevenDigits(value: string) {
47+
let sum = 0;
48+
let rest = 0;
49+
let validatorDigit = 0;
50+
let pis = '';
51+
let result = '';
52+
const cnsSize = value.length;
53+
54+
if (cnsSize !== 15) {
55+
return false;
56+
}
57+
58+
pis = value.substring(0, 11);
59+
sum =
60+
Number(pis.substring(0, 1)) * 15 +
61+
Number(pis.substring(1, 2)) * 14 +
62+
Number(pis.substring(2, 3)) * 13 +
63+
Number(pis.substring(3, 4)) * 12 +
64+
Number(pis.substring(4, 5)) * 11 +
65+
Number(pis.substring(5, 6)) * 10 +
66+
Number(pis.substring(6, 7)) * 9 +
67+
Number(pis.substring(7, 8)) * 8 +
68+
Number(pis.substring(8, 9)) * 7 +
69+
Number(pis.substring(9, 10)) * 6 +
70+
Number(pis.substring(10, 11)) * 5;
71+
rest = sum % 11;
72+
validatorDigit = 11 - rest;
73+
74+
if (validatorDigit === 11) {
75+
validatorDigit = 0;
76+
}
77+
78+
if (validatorDigit === 10) {
79+
sum =
80+
Number(pis.substring(0, 1)) * 15 +
81+
Number(pis.substring(1, 2)) * 14 +
82+
Number(pis.substring(2, 3)) * 13 +
83+
Number(pis.substring(3, 4)) * 12 +
84+
Number(pis.substring(4, 5)) * 11 +
85+
Number(pis.substring(5, 6)) * 10 +
86+
Number(pis.substring(6, 7)) * 9 +
87+
Number(pis.substring(7, 8)) * 8 +
88+
Number(pis.substring(8, 9)) * 7 +
89+
Number(pis.substring(9, 10)) * 6 +
90+
Number(pis.substring(10, 11)) * 5 +
91+
2;
92+
rest = sum % 11;
93+
validatorDigit = 11 - rest;
94+
result = `${pis}001${String(validatorDigit)}`;
95+
} else {
96+
result = `${pis}000${String(validatorDigit)}`;
97+
}
98+
99+
if (value !== result) {
100+
return false;
101+
}
102+
103+
return true;
104+
}
105+
106+
/**
107+
* Valida CNS com e sem máscara.
108+
*
109+
* @param { string } value
110+
* @returns { boolean }
111+
*/
112+
export function cnsValidator(value: string) {
113+
if (typeof value !== 'string') {
114+
throw new Error('O tipo do parâmetro passado é inválido.');
115+
}
116+
117+
const unmaskedValue = value.replace(/\D/g, '');
118+
119+
if (unmaskedValue.length !== 15) {
120+
return false;
121+
}
122+
123+
if ([1, 2].indexOf(parseInt(unmaskedValue.substring(0, 1))) != -1) {
124+
return checkCnsFirstElevenDigits(unmaskedValue);
125+
}
126+
127+
return checkCnsValue(unmaskedValue);
128+
}

tests/cnsValidator.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { describe, expect, test } from 'vitest';
2+
import { cnsValidator } from '../src/utils/cnsValidator';
3+
4+
describe('cnsValidator()', () => {
5+
test('retorna false quando string vazia é passada', () => {
6+
expect(cnsValidator('')).toBe(false);
7+
});
8+
9+
test('retorna false quando cns inválido com máscara é passado', () => {
10+
expect(cnsValidator('111 1111 1111 1111')).toBe(false);
11+
});
12+
13+
test('retorna true quando cns válido com máscara é passado', () => {
14+
expect(cnsValidator('728 1376 2535 3587')).toBe(true);
15+
});
16+
17+
test('retorna false quando cns inválido sem máscara é passado', () => {
18+
expect(cnsValidator('111111111111111')).toBe(false);
19+
});
20+
21+
test('retorna true quando cns válido sem máscara é passado', () => {
22+
expect(cnsValidator('728137625353587')).toBe(true);
23+
});
24+
25+
test('retorna false quando cns possui menos que 15 dígitos', () => {
26+
expect(cnsValidator('11111111111')).toBe(false);
27+
});
28+
29+
test('retorna false quando cns possui mais que 15 dígitos', () => {
30+
expect(cnsValidator('7281376253535879')).toBe(false);
31+
});
32+
33+
test('retorna false quando cns possui uma letra', () => {
34+
expect(cnsValidator('11111111111111a')).toBe(false);
35+
});
36+
37+
test('lança erro quando parâmetro é do tipo number', () => {
38+
expect(() => cnsValidator(12341789324)).toThrowError();
39+
});
40+
});

0 commit comments

Comments
 (0)