diff --git a/src/index.ts b/src/index.ts index 1a01659..aa6d483 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ export { default as normalizeSocialNumber } from './normalizers/normalizeSocialN // utils export { default as maskString } from './utils/maskString'; export { default as stripNumbers } from './utils/stripNumbers'; +export { default as stripCpfCnpj } from './utils/stripCpfCnpj'; export { default as getStates } from './utils/getStates'; export { default as snakeToCamel } from './utils/snakeToCamel'; export { default as camelToSnake } from './utils/camelToSnake'; diff --git a/src/utils/stripCpfCnpj.ts b/src/utils/stripCpfCnpj.ts new file mode 100644 index 0000000..a40a379 --- /dev/null +++ b/src/utils/stripCpfCnpj.ts @@ -0,0 +1,25 @@ +import { stripAlphanumeric } from '../masks/strip'; + +/** + * Sanitiza um CPF/CNPJ removendo os separadores da máscara (qualquer caractere + * não-alfanumérico: `.`, `/`, `-`, espaços) e normalizando para upper-case, + * **preservando as letras** do CNPJ alfanumérico (Receita Federal — + * Nota Técnica NT 49/2024, vigente a partir de 2026). + * + * Use no lugar de `stripNumbers` / `value.replace(/\D/g, '')` em qualquer fluxo + * de CNPJ (validação, envio, lookup, navegação): essas abordagens descartam as + * letras A–Z e transformam um CNPJ alfanumérico válido em um identificador + * inválido. + * + * É o inverso de {@link normalizeCpfOrCnpj} (que aplica a máscara visual). + * + * @example + * stripCpfCnpj('824.007.050-70'); // '82400705070' (CPF) + * stripCpfCnpj('12.345.678/0001-95'); // '12345678000195' (CNPJ numérico) + * stripCpfCnpj('AB.345.678/XY01-74'); // 'AB345678XY0174' (CNPJ alfanumérico) + * stripCpfCnpj('ab.345.678/xy01-74'); // 'AB345678XY0174' (normaliza upper-case) + * stripCpfCnpj(undefined); // '' + */ +export default function stripCpfCnpj(value?: string): string { + return stripAlphanumeric(value ?? ''); +} diff --git a/tests/stripCpfCnpj.spec.ts b/tests/stripCpfCnpj.spec.ts new file mode 100644 index 0000000..3a5cf59 --- /dev/null +++ b/tests/stripCpfCnpj.spec.ts @@ -0,0 +1,32 @@ +import 'jest'; + +import { stripCpfCnpj } from '../src'; + +describe('stripCpfCnpj', () => { + test('CPF mascarado → apenas dígitos', () => { + expect(stripCpfCnpj('824.007.050-70')).toBe('82400705070'); + }); + + test('CNPJ numérico mascarado → apenas dígitos', () => { + expect(stripCpfCnpj('12.345.678/0001-95')).toBe('12345678000195'); + }); + + // RFB NT 49/2024 — as letras fazem parte do identificador e não podem ser + // descartadas (o que aconteceria com stripNumbers / /\D/g). + test('CNPJ alfanumérico preserva as letras', () => { + expect(stripCpfCnpj('AB.345.678/XY01-74')).toBe('AB345678XY0174'); + }); + + test('CNPJ alfanumérico minúsculo é normalizado para upper-case', () => { + expect(stripCpfCnpj('ab.345.678/xy01-74')).toBe('AB345678XY0174'); + }); + + test('valor já sem máscara é idempotente', () => { + expect(stripCpfCnpj('AB345678XY0174')).toBe('AB345678XY0174'); + }); + + test('undefined / vazio → string vazia', () => { + expect(stripCpfCnpj(undefined)).toBe(''); + expect(stripCpfCnpj('')).toBe(''); + }); +});