-
-
Save alexbruno/6623b5afa847f891de9cb6f704d86d02 to your computer and use it in GitHub Desktop.
| // Regex para validação de string no formato CNPJ | |
| export const regexCNPJ = /^\d{2}.\d{3}.\d{3}\/\d{4}-\d{2}$/ | |
| // Método de validação | |
| // Referência: https://pt.wikipedia.org/wiki/Cadastro_Nacional_da_Pessoa_Jur%C3%ADdica | |
| export function validCNPJ(value: string | number | number[] = '') { | |
| if (!value) return false | |
| // Aceita receber o valor como string, número ou array com todos os dígitos | |
| const isString = typeof value === 'string' | |
| const validTypes = isString || Number.isInteger(value) || Array.isArray(value) | |
| // Elimina valor de tipo inválido | |
| if (!validTypes) return false | |
| // Filtro inicial para entradas do tipo string | |
| if (isString) { | |
| // Teste Regex para veificar se é uma string apenas dígitos válida | |
| const digitsOnly = /^\d{14}$/.test(value) | |
| // Teste Regex para verificar se é uma string formatada válida | |
| const validFormat = regexCNPJ.test(value) | |
| // Verifica se o valor passou em ao menos 1 dos testes | |
| const isValid = digitsOnly || validFormat | |
| // Se o formato não é válido, retorna inválido | |
| if (!isValid) return false | |
| } | |
| // Elimina tudo que não é dígito | |
| const numbers = matchNumbers(value) | |
| // Valida a quantidade de dígitos | |
| if (numbers.length !== 14) return false | |
| // Elimina inválidos com todos os dígitos iguais | |
| const items = [...new Set(numbers)] | |
| if (items.length === 1) return false | |
| // Separa os 2 últimos dígitos verificadores | |
| const digits = numbers.slice(12) | |
| // Valida 1o. dígito verificador | |
| const digit0 = validCalc(12, numbers) | |
| if (digit0 !== digits[0]) return false | |
| // Valida 2o. dígito verificador | |
| const digit1 = validCalc(13, numbers) | |
| return digit1 === digits[1] | |
| } | |
| // Método de formatação | |
| export function formatCNPJ(value: string | number | number[] = '') { | |
| // Verifica se o valor é válido | |
| const valid = validCNPJ(value) | |
| // Se o valor não for válido, retorna vazio | |
| if (!valid) return '' | |
| // Elimina tudo que não é dígito | |
| const numbers = matchNumbers(value) | |
| const text = numbers.join('') | |
| // Formatação do CNPJ: 99.999.999/9999-99 | |
| const format = text.replace( | |
| /(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, | |
| '$1.$2.$3/$4-$5', | |
| ) | |
| // Retorna o valor formatado | |
| return format | |
| } | |
| // Cálculo validador | |
| function validCalc(x: number, numbers: number[]) { | |
| const slice = numbers.slice(0, x) | |
| let factor = x - 7 | |
| let sum = 0 | |
| for (let i = x; i >= 1; i--) { | |
| const n = slice[x - i] | |
| sum += n * factor-- | |
| if (factor < 2) factor = 9 | |
| } | |
| const result = 11 - (sum % 11) | |
| return result > 9 ? 0 : result | |
| } | |
| // Elimina tudo que não é dígito | |
| function matchNumbers(value: string | number | number[] = '') { | |
| const match = value.toString().match(/\d/g) | |
| return Array.isArray(match) ? match.map(Number) : [] | |
| } |
Sensacional irmão! Apenas um ponto, da linha 22 até a 24 deu erro aqui em 18/05/2023, então substituí pelo trecho abaixo:
return digitsOnly || validFormat;
Sensacional irmão! Apenas um ponto, da linha 22 até a 24 deu erro aqui em 18/05/2023, então substituí pelo trecho abaixo:
return digitsOnly || validFormat;
É @jorgemustafa, já saquei o erro, o código que usei ali na época não é uma boa prática atualmente.
Retornar naquele ponto como você fez não é o suficiente, pois se você passar uma string de CNPJ com formato válido mas que não seja um CNPJ válido de fato segundo o algoritmo de validação, você terá um falso positivo.
Atualizei o código corrigindo o erro. Obrigado pela contribuição!
O HOMEM É BRABOOO!!
Código atualizado:
- TypeScript para maior clareza dos tipos de dados
- Separação de funções reutilizáveis para maior clareza do que acontece no geral
- Bônus: Método de formatação CNPJ
Ajustes + Testes com JestJs
import { validCNPJ } from './validate-cnpj';
describe('validCNPJ', () => {
it('should validate a valid CNPJ', () => {
expect(validCNPJ('04.470.781/0001-39')).toBeTruthy();
});
it('should invalidate an invalid CNPJ', () => {
expect(validCNPJ('11.111.111/1111-11')).toBeFalsy();
});
it('should return false for an invalid CNPJ', () => {
const cnpj = '34.574.376/0001-93';
expect(validCNPJ(cnpj)).toBeFalsy();
});
it('should return false for a CNPJ with all identical digits', () => {
const cnpj = '11.111.111/1111-11';
expect(validCNPJ(cnpj)).toBeFalsy();
});
it('should return false for a CNPJ with incorrect length', () => {
const cnpj = '34.574.376/0001';
expect(validCNPJ(cnpj)).toBeFalsy();
});
it('should return false for a CNPJ with non-numeric characters', () => {
const cnpj = '34a574b376/0001c92';
expect(validCNPJ(cnpj)).toBeFalsy();
});
it('should return false for an empty string', () => {
const cnpj = '';
expect(validCNPJ(cnpj)).toBeFalsy();
});
it('should return false for a null value', () => {
const cnpj = null;
expect(validCNPJ(cnpj)).toBeFalsy();
});
});
Os dois primeiros tests quebraram, fiz ajuste na func para funcionar.
atualizei o regex para ficar dessa forma, ficando mas especifica para o metodo.
export const regexCNPJ = /^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/;
export const validCNPJ = (value: string | number | number[] = '') => {
if (!value) return false;
const isString = typeof value === 'string';
if (isString && !regexCNPJ.test(value)) return false;
const numbers = matchNumbers(value);
if (numbers.length !== 14) return false;
const items = [...new Set(numbers)];
if (items.length === 1) return false;
const digit0 = validCalc(12, numbers);
const digit1 = validCalc(13, numbers);
return digit0 === numbers[12] && digit1 === numbers[13];
};
function validCalc(x: number, numbers: number[]) {
let factor = x - 7;
let sum = 0;
for (let i = 0; i < x; i++) {
sum += numbers[i] * factor--;
if (factor < 2) factor = 9;
}
const result = 11 - (sum % 11);
return result > 9 ? 0 : result;
}
function matchNumbers(value: string | number | number[] = '') {
const match = value
.toString()
.replace(/[^\d]+/g, '')
.match(/\d/g);
return Array.isArray(match) ? match.map(Number) : [];
}
`
Salvou demais! Valeu
e eu agradeço a todos vocês pela contribuição usarei esse método agora e ta quebrando um galho kk