Skip to content
Merged
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
74 changes: 74 additions & 0 deletions docs/utils/cnsValidator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# CnsValidator

Utilitário para validar CNS com e sem máscara.

## Instalação e Importação

```typescript
import { cnsValidator } from '@sysvale/foundry';
```

## Função

### `cnsValidator()`

Valida CNS com e sem máscara, indicando se os mesmos são válidos.

#### Sintaxes

```typescript
cnsValidator(value: string): boolean
```

#### Parâmetros

**Assinatura 1:**

- **`value`** (`string`): CNS (com ou sem máscara) a ser validado

<br />

#### Retorno

`boolean` - Resultado da validação, `true` para CNS válido e `false` para inválido

<br />

#### Exemplos

**Usando CNS com máscara:**

```typescript
cnsValidator('728 1376 2535 3587'); // → true

cnsValidator('111 1111 1111 1111'); // → false
```

<br />

**Usando CNS sem máscara:**

```typescript
cnsValidator('728137625353587'); // → true

cnsValidator('111111111111111'); // → false
```

<br />

#### Tratamento de Erros

A função lança um erro quando os parâmetros obrigatórios não são fornecidos:

```typescript
// ❌ Erro: tipagem do parâmetro é inválida
cnsValidator(728137625353587);
// → Error: O tipo do parâmetro passado é inválido.

// ✅ Correto
cnsValidator('728137625353587');
```

## Notas

- A função é **type-safe**
6 changes: 6 additions & 0 deletions docs/utils/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ Função para sanitizar dados de formulário e aplicar transformações antes de
Função para validar CPFs com e sem máscara.

- [Documentação](./cpfValidator.md)

### cnsValidator()

Função para validar CNS com e sem máscara.

- [Documentação](./cnsValidator.md)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sysvale/foundry",
"version": "1.6.0",
"version": "1.7.0",
"description": "A forge for composables, helpers, and front-end utilities.",
"type": "module",
"main": "./dist/foundry.cjs.js",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './utils/pluralize';
export * from './utils/commaline';
export * from './utils/sanitizeForm';
export * from './utils/cpfValidator';
export * from './utils/cnsValidator';
export { maskCpf, removeCpfMask } from './formatters/cpf';
export { maskCns, removeCnsMask } from './formatters/cns';
export { maskPhone, removePhoneMask } from './formatters/phone';
Expand Down
128 changes: 128 additions & 0 deletions src/utils/cnsValidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
function checkCnsValue(value: string) {
let pis;
let rest;
let sum;

pis = value.substring(0, 15);

if (pis === '') {
return false;
}

if (
value.substring(0, 1) !== '7' &&
value.substring(0, 1) !== '8' &&
value.substring(0, 1) !== '9'
) {
return false;
}

sum =
parseInt(pis.substring(0, 1), 10) * 15 +
parseInt(pis.substring(1, 2), 10) * 14 +
parseInt(pis.substring(2, 3), 10) * 13 +
parseInt(pis.substring(3, 4), 10) * 12 +
parseInt(pis.substring(4, 5), 10) * 11 +
parseInt(pis.substring(5, 6), 10) * 10 +
parseInt(pis.substring(6, 7), 10) * 9 +
parseInt(pis.substring(7, 8), 10) * 8 +
parseInt(pis.substring(8, 9), 10) * 7 +
parseInt(pis.substring(9, 10), 10) * 6 +
parseInt(pis.substring(10, 11), 10) * 5 +
parseInt(pis.substring(11, 12), 10) * 4 +
parseInt(pis.substring(12, 13), 10) * 3 +
parseInt(pis.substring(13, 14), 10) * 2 +
parseInt(pis.substring(14, 15), 10) * 1;

rest = sum % 11;

if (!rest) {
return true;
}

return false;
}

function checkCnsFirstElevenDigits(value: string) {
let sum = 0;
let rest = 0;
let validatorDigit = 0;
let pis = '';
let result = '';
const cnsSize = value.length;

if (cnsSize !== 15) {
return false;
}

pis = value.substring(0, 11);
sum =
Number(pis.substring(0, 1)) * 15 +
Number(pis.substring(1, 2)) * 14 +
Number(pis.substring(2, 3)) * 13 +
Number(pis.substring(3, 4)) * 12 +
Number(pis.substring(4, 5)) * 11 +
Number(pis.substring(5, 6)) * 10 +
Number(pis.substring(6, 7)) * 9 +
Number(pis.substring(7, 8)) * 8 +
Number(pis.substring(8, 9)) * 7 +
Number(pis.substring(9, 10)) * 6 +
Number(pis.substring(10, 11)) * 5;
rest = sum % 11;
validatorDigit = 11 - rest;

if (validatorDigit === 11) {
validatorDigit = 0;
}

if (validatorDigit === 10) {
sum =
Number(pis.substring(0, 1)) * 15 +
Number(pis.substring(1, 2)) * 14 +
Number(pis.substring(2, 3)) * 13 +
Number(pis.substring(3, 4)) * 12 +
Number(pis.substring(4, 5)) * 11 +
Number(pis.substring(5, 6)) * 10 +
Number(pis.substring(6, 7)) * 9 +
Number(pis.substring(7, 8)) * 8 +
Number(pis.substring(8, 9)) * 7 +
Number(pis.substring(9, 10)) * 6 +
Number(pis.substring(10, 11)) * 5 +
2;
rest = sum % 11;
validatorDigit = 11 - rest;
result = `${pis}001${String(validatorDigit)}`;
} else {
result = `${pis}000${String(validatorDigit)}`;
}

if (value !== result) {
return false;
}

return true;
}

/**
* Valida CNS com e sem máscara.
*
* @param { string } value
* @returns { boolean }
*/
export function cnsValidator(value: string) {
if (typeof value !== 'string') {
throw new Error('O tipo do parâmetro passado é inválido.');
}

const unmaskedValue = value.replace(/\D/g, '');

if (unmaskedValue.length !== 15) {
return false;
}

if ([1, 2].indexOf(parseInt(unmaskedValue.substring(0, 1))) != -1) {
return checkCnsFirstElevenDigits(unmaskedValue);
}

return checkCnsValue(unmaskedValue);
}
40 changes: 40 additions & 0 deletions tests/cnsValidator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, test } from 'vitest';
import { cnsValidator } from '../src/utils/cnsValidator';

describe('cnsValidator()', () => {
test('retorna false quando string vazia é passada', () => {
expect(cnsValidator('')).toBe(false);
});

test('retorna false quando cns inválido com máscara é passado', () => {
expect(cnsValidator('111 1111 1111 1111')).toBe(false);
});

test('retorna true quando cns válido com máscara é passado', () => {
expect(cnsValidator('728 1376 2535 3587')).toBe(true);
});

test('retorna false quando cns inválido sem máscara é passado', () => {
expect(cnsValidator('111111111111111')).toBe(false);
});

test('retorna true quando cns válido sem máscara é passado', () => {
expect(cnsValidator('728137625353587')).toBe(true);
});

test('retorna false quando cns possui menos que 15 dígitos', () => {
expect(cnsValidator('11111111111')).toBe(false);
});

test('retorna false quando cns possui mais que 15 dígitos', () => {
expect(cnsValidator('7281376253535879')).toBe(false);
});

test('retorna false quando cns possui uma letra', () => {
expect(cnsValidator('11111111111111a')).toBe(false);
});

test('lança erro quando parâmetro é do tipo number', () => {
expect(() => cnsValidator(12341789324)).toThrowError();
});
});