Skip to content

Instantly share code, notes, and snippets.

@alisterlf
Last active August 13, 2021 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alisterlf/4e7a0e4c0208659ea48909dc6bad14ed to your computer and use it in GitHub Desktop.
Save alisterlf/4e7a0e4c0208659ea48909dc6bad14ed to your computer and use it in GitHub Desktop.
Validador e formatador de CPF e CNPJ com Typescript
import { CpfCnpjUtils } from './cpf-cnpj.utils';
describe('Cpf and Cnpj Utils', () => {
describe('Cpf', () => {
describe('format', () => {
it('Should return CPF with dots and dash', () => {
expect(CpfCnpjUtils.formatCpf('13768663663')).toBe('137.686.636-63');
});
});
it('Should return false to an empty string', () => {
expect(CpfCnpjUtils.isCpfValid('')).toBeFalsy();
});
it('Should return true to a valid CPF starting with 0', () => {
expect(CpfCnpjUtils.isCpfValid('06325112733')).toBeTruthy();
});
it('Should return true to a valid CPF just with digits', () => {
expect(CpfCnpjUtils.isCpfValid('13768663663')).toBeTruthy();
});
it('Should return true to a valid CPF with separator -', () => {
expect(CpfCnpjUtils.isCpfValid('137686636-63')).toBeTruthy();
});
it('Should return true to a valid CPF with separator - and .', () => {
expect(CpfCnpjUtils.isCpfValid('137.686.636-63')).toBeTruthy();
});
it('Should return false when is not a valid CPF just with digits', () => {
expect(CpfCnpjUtils.isCpfValid('06487598710')).toBeFalsy();
});
it('Should return false when is not a valid CPF with separator -', () => {
expect(CpfCnpjUtils.isCpfValid('064875987-10')).toBeFalsy();
});
it('Should return false when is not a valid CPF with separator - and .', () => {
expect(CpfCnpjUtils.isCpfValid('064.875.987-10')).toBeFalsy();
});
it('Should return false when is mixing digits and letter', () => {
expect(CpfCnpjUtils.isCpfValid('a064.875.987-10')).toBeFalsy();
});
it('Should return false to special caracters', () => {
expect(CpfCnpjUtils.isCpfValid('0&.*00.00a-00')).toBeFalsy();
});
it('Should return false is 11 repeat digits', () => {
expect(CpfCnpjUtils.isCpfValid('00000000000')).toBeFalsy();
});
it('Verificador 1 = 0', () => {
expect(CpfCnpjUtils.isCpfValid('76381842202')).toBeTruthy();
});
it('Verificador 1 > 1', () => {
expect(CpfCnpjUtils.isCpfValid('125.828.106-65')).toBeTruthy();
});
it('Verificador 2 = 0', () => {
expect(CpfCnpjUtils.isCpfValid('433.787.588-30')).toBeTruthy();
});
it('Verificador 2 > 1', () => {
expect(CpfCnpjUtils.isCpfValid('855.178.021-25')).toBeTruthy();
});
});
describe('Cnpj', () => {
describe('format', () => {
it('Should return CNPJ with dots, slash and dash', () => {
expect(CpfCnpjUtils.formatCnpj('26149878000187')).toBe('26.149.878/0001-87');
});
});
it('Should return true to a valid CNPJ starting with 0', () => {
expect(CpfCnpjUtils.isCnpjValid('06860123000189')).toBeTruthy();
});
it('Should return true to a valid CNPJ just with digits', () => {
expect(CpfCnpjUtils.isCnpjValid('26533854000127')).toBeTruthy();
});
it('Should return true to a valid CNPJ with separator -', () => {
expect(CpfCnpjUtils.isCnpjValid('261498780001-87')).toBeTruthy();
});
it('Should return true to a valid CNPJ with separator - and /', () => {
expect(CpfCnpjUtils.isCnpjValid('26149878/0001-87')).toBeTruthy();
});
it('Should return true to a valid CNPJ with separator - and / and .', () => {
expect(CpfCnpjUtils.isCnpjValid('26.149.878/0001-87')).toBeTruthy();
});
it('Should return false when is not a valid CNPJ just with digits', () => {
expect(CpfCnpjUtils.isCnpjValid('06860123000188')).toBeFalsy();
});
it('Should return false when is not a valid CNPJ with separator -', () => {
expect(CpfCnpjUtils.isCnpjValid('068601230001-88')).toBeFalsy();
});
it('Should return false when is not a valid CNPJ with separator - and / and .', () => {
expect(CpfCnpjUtils.isCnpjValid('26.149.878/0001-88')).toBeFalsy();
});
it('Should return false when is mixing digits and letter', () => {
expect(CpfCnpjUtils.isCnpjValid('a1.775.044/0001-31')).toBeFalsy();
});
it('Should return false to special caracters', () => {
expect(CpfCnpjUtils.isCnpjValid('*1.775.044/0001-31')).toBeFalsy();
});
it('Should return false is 14 repeat digits', () => {
expect(CpfCnpjUtils.isCnpjValid('00000000000000')).toBeFalsy();
});
it('Should return true to a valid CNPJ with first checker = 0', () => {
expect(CpfCnpjUtils.isCnpjValid('04.096.776/0001-08')).toBeTruthy();
});
it('Should return true to a valid CNPJ with first checker 1 >= 1', () => {
expect(CpfCnpjUtils.isCnpjValid('29.613.398/0001-13')).toBeTruthy();
});
it('Should return true to a valid CNPJ with second checker = 0', () => {
expect(CpfCnpjUtils.isCnpjValid('35.661.025/0001-10')).toBeTruthy();
});
it('Should return true to a valid CNPJ with second checker 2 >= 1', () => {
expect(CpfCnpjUtils.isCnpjValid('53.638.687/0001-51')).toBeTruthy();
});
});
});
export class CpfCnpjUtils {
static isCpfValid(cpf: string): boolean {
const cpfLength = 11;
return this.isValid(cpf, cpfLength);
}
static isCnpjValid(cnpj: string): boolean {
const cpfLength = 14;
return this.isValid(cnpj, cpfLength);
}
static formatCpf(cpf: string): string {
const correctDigitsLength = 11;
const firstDotPosition = 2;
const secondDotPosition = 5;
const slashPosition = -1;
const dashPosition = 8;
return this.format(
cpf,
correctDigitsLength,
firstDotPosition,
secondDotPosition,
slashPosition,
dashPosition,
);
}
static formatCnpj(cnpj: string): string {
const correctDigitsLength = 14;
const firstDotPosition = 1;
const secondDotPosition = 4;
const slashPosition = 7;
const dashPosition = 11;
return this.format(
cnpj,
correctDigitsLength,
firstDotPosition,
secondDotPosition,
slashPosition,
dashPosition,
);
}
private static format(
digits: string,
correctDigitsLength: number,
firstDotPosition: number,
secondDotPosition: number,
slashPosition: number,
dashPosition: number,
): string {
const cleanDigits = this.getOnlyNumbers(digits);
return cleanDigits
.slice(0, correctDigitsLength)
.split('')
.reduce((acc, digit, idx) => {
const result = `${acc}${digit}`;
if (idx !== digits.length - 1) {
if (idx === firstDotPosition || idx === secondDotPosition) {
return `${result}.`;
}
if (idx === slashPosition) {
return `${result}/`;
}
if (idx === dashPosition) {
return `${result}-`;
}
}
return result;
}, '');
}
private static isValid(digits: string, correctDigitsLength: number): boolean {
const cleanDigits = this.getOnlyNumbers(digits);
if (
cleanDigits.length !== correctDigitsLength ||
this.isAllTheSameDigits(cleanDigits)
) {
return false;
}
const digitsWithoutChecker = cleanDigits.substring(
0,
correctDigitsLength - 2,
);
const digitsChecker = cleanDigits.substring(
correctDigitsLength - 2,
correctDigitsLength,
);
const calculatedChecker = this.calcChecker(digitsWithoutChecker);
return digitsChecker === calculatedChecker;
}
private static getOnlyNumbers(digits: string): string {
return digits.replace(/\D/g, '');
}
private static isAllTheSameDigits(digits: string): boolean {
return !digits.split('').some((digit) => digit !== digits[0]);
}
private static calcChecker(digits: string): string {
const digitsLength = digits.length;
const digitsLengthWithoutChecker = digitsLength < 11 ? 9 : 12;
const weight = digitsLength < 11 ? digitsLength + 1 : digitsLength - 7;
const sum = digits.split('').reduce((acc, digit, idx) => {
const offsetValue = weight - idx >= 2 ? 0 : 8;
return acc + +digit * (weight + offsetValue - idx);
}, 0);
const sumDivisionRemainder = sum % 11;
const checker = sumDivisionRemainder < 2 ? 0 : 11 - sumDivisionRemainder;
if (digitsLength === digitsLengthWithoutChecker) {
return this.calcChecker(`${digits}${checker}`);
}
return `${digits[digitsLength - 1]}${checker}`;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment