Last active
August 13, 2021 00:47
-
-
Save alisterlf/4e7a0e4c0208659ea48909dc6bad14ed to your computer and use it in GitHub Desktop.
Validador e formatador de CPF e CNPJ com Typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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