Skip to content

feat: adiciona máscaras de input e suporte a CNPJ alfanumérico#33

Merged
FabioRolin merged 5 commits into
masterfrom
feat/cnpj-alphanumeric-and-input-masks
May 8, 2026
Merged

feat: adiciona máscaras de input e suporte a CNPJ alfanumérico#33
FabioRolin merged 5 commits into
masterfrom
feat/cnpj-alphanumeric-and-input-masks

Conversation

@FabioRolin
Copy link
Copy Markdown
Contributor

@FabioRolin FabioRolin commented May 7, 2026

Tipo de mudança

feature

Contexto

Atualmente 34 MFEs do ecossistema mantêm cópias quase idênticas de src/utils/masks.ts/masks.js baseadas em vanilla-masker, gerando manutenção pulverizada. Além disso, a Receita Federal está adotando o CNPJ alfanumérico (Nota Técnica RFB NT 49/2024) — letras A-Z nas 12 primeiras posições + 2 dígitos verificadores numéricos —, e as funções atuais de formatCnpj, normalizeCpfOrCnpj e isCnpj no blu-utils usam replace(/\D/g, '')/regex puramente numérica, destruindo silenciosamente as letras.

Esta PR é a Fase 1 descrita no PRD: centralizar todas as máscaras de input no @useblu/utils (já re-exportado pelo mfe-core como core/blu-utils via Module Federation) e atualizar as funções existentes para suportarem o novo formato. A Fase 2 (migração dos 34 MFEs para consumirem core/blu-utils em vez dos arquivos locais) ficará para depois.

Solução

Novo módulo src/masks/

Reúne em um lugar único: maskValue, maskInput, maskCpf, maskCpfOrCnpj, maskComplete, setupMultipleMask, maskHintBankAccount.

  • Engine de máscara: vanilla-masker (adicionado como dependency) — placeholders 9 (dígito), S (alfanumérico), A (letra). CNPJ usa pattern SS.SSS.SSS/SSSS-99 (12 alfa + 2 dígito).
  • Validação de CNPJ: isCnpj.ts virou wrapper sobre cpf-cnpj-validator@2.1.0 (cnpj.isValid(value.toUpperCase())), que já implementa o algoritmo de DV alfanumérico oficial e mantém blacklist de CNPJs inválidos. A blacklist e o verifierDigit locais foram removidos (a lib cuida).
  • Normalização: todo CNPJ é normalizado para .toUpperCase() no ponto de entrada via helper stripAlphanumeric (regex /[^A-Za-z0-9]/g + uppercase). Helpers de strip centralizados em src/masks/strip.ts para evitar duplicação de regex em 6+ arquivos.

API pública enxuta

Após análise de uso real nos MFEs, não foram expostos: masks (constante), cnpjMask, cpfMask, bankAccountMasks, maskBankAccount. A constante interna foi renomeada masksMASKS com chaves UPPERCASE para deixar claro que é detalhe de implementação.

Retrocompatibilidade

  • formatCnpj, normalizeCpfOrCnpj e isCnpj mantêm a mesma assinatura. CNPJ numérico continua funcionando exatamente como antes (cobertura via testes de regressão).
  • O parâmetro strict de isCnpj perde efeito prático (a cpf-cnpj-validator aceita ambos os formatos). Marcado como @deprecated no JSDoc.

Principais mudanças

  • Novo módulo src/masks/ com 9 arquivos (types.ts, masks.ts, strip.ts, maskValue.ts, maskInput.ts, maskCpf.ts, maskCpfOrCnpj.ts, maskComplete.ts, setupMultipleMask.ts, maskHintBankAccount.ts, vanilla-masker.d.ts)
  • src/formatters/formatCnpj.ts reescrito para usar stripAlphanumeric + VMasker.toPattern(stripped, MASKS.CNPJ)
  • src/normalizers/normalizeCpfOrCnpj.ts atualizado para CNPJ alfanumérico (>11 chars limpos)
  • src/validations/isCnpj.ts virou wrapper de 4 linhas sobre cpf-cnpj-validator
  • src/index.ts adiciona bloco // masks com 7 funções e 3 types públicos
  • package.json: vanilla-masker@^1.2.0 e cpf-cnpj-validator@2.1.0 em dependencies; jest-environment-jsdom@29 em devDependencies (necessário para testes do maskInput)
  • 8 arquivos de teste novos em tests/masks/ + tests/formatCnpj.spec.ts; tests/isCnpj.spec.ts e tests/normalizeCpfOrCnpj.spec.ts estendidos com casos de CNPJ alfanumérico

Impacto

  • Escopo: apenas o pacote @useblu/utils. Nenhum MFE é afetado nesta entrega — a migração para core/blu-utils é Fase 2.
  • Risco: baixo — assinaturas públicas mantidas, suíte de testes existente passa intacta, novas funções são puramente aditivas.
  • Bundle size: ~11.5KB gzip agregado (vanilla-masker ~3KB + cpf-cnpj-validator ~7KB + código novo ~1.5KB). Discutido e aceito no spec (RNF-03 do PRD revogado).

Cenários de teste

  • maskValue('11222333000181', 'cnpj')'11.222.333/0001-81' (numérico — retrocompat)
  • maskValue('12ABC34501DE35', 'cnpj')'12.ABC.345/01DE-35' (alfanumérico)
  • maskValue('12abc34501de35', 'cnpj')'12.ABC.345/01DE-35' (minúsculo normaliza)
  • maskCpfOrCnpj('93231097037')'932.310.970-37' (CPF, ≤11 chars)
  • maskCpfOrCnpj('12ABC34501DE35')'12.ABC.345/01DE-35' (CNPJ alfa, >11 chars)
  • maskInput(input, 'cpf') aplica máscara em tempo real ao digitar e pode ser desfeito via teardown
  • setupMultipleMask(input) transiciona de CPF → CNPJ ao digitar o 12º caractere
  • isCnpj(cnpj.generate())true (CNPJ alfa válido gerado pela própria lib)
  • isCnpj('12ABC34501DE99')false (DV alfa errado)
  • isCnpj('00000000000000')false (blacklist numérica preservada via lib)
  • formatCnpj('11222333000181')'11.222.333/0001-81' (regressão numérica)
  • formatCnpj('12abc34501de35')'12.ABC.345/01DE-35' (alfa + uppercase)
  • maskComplete('12.ABC.345/01DE-35', 'cnpj')true
  • maskHintBankAccount('1')'00000000-0' (BB)

Validações automáticas: yarn build, yarn lint, yarn test --testPathPattern=\"masks|formatCnpj|isCnpj|normalizeCpfOrCnpj\" (10 suítes, 63 testes verdes localmente).

Breaking changes

Nenhum em assinaturas públicas. Mudanças de comportamento documentar no CHANGELOG da 1.3.0:

  • formatCnpj agora preserva letras A-Z e normaliza para uppercase. MFEs que assumiam retorno numérico devem ser auditados na Fase 2.
  • isCnpj(value, strict) ignora strict (soft deprecation). A lib cpf-cnpj-validator aceita ambos os formatos por padrão.
  • verifierDigit antes exportado como named export em src/validations/isCnpj.ts foi removido (decisão registrada no spec).

Dependências entre PRs

  • Pós-merge: PR no Pagnet/mfe-core bumpando @useblu/utils para 1.3.0 é hand-off para a squad Core (T9 do plano de execução do spec).

Rollback

  • Rollback seguro? Sim
  • Procedimento: npm deprecate @useblu/utils@1.3.0 + revert do bump no mfe-core quando aplicado. Como nenhum MFE consome a nova API ainda, o impacto de rollback é zero no curto prazo.

Links

FabioRolin and others added 4 commits May 7, 2026 15:10
Centralizes mask functions previously scattered across 34 MFEs.
Adds support for the alphanumeric CNPJ format (RFB NT 49/2024)
in formatCnpj, normalizeCpfOrCnpj, and isCnpj.

- New module src/masks/ exposing: maskValue, maskInput, maskCpf,
  maskCpfOrCnpj, maskComplete, setupMultipleMask, maskHintBankAccount
- isCnpj is now a wrapper over cpf-cnpj-validator@2.1.0 with
  uppercase normalization (handles both numeric and alphanumeric CNPJ)
- formatCnpj and normalizeCpfOrCnpj preserve A-Z characters
- Strip regexes centralized in src/masks/strip.ts
- vanilla-masker added as runtime dependency

Refs #32

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
actions/cache@v2 was deprecated and started auto-failing builds.
cpf-cnpj-validator@2.1.0 (added in this branch) requires Node >=18,
breaking the linter job that pinned Node 16.

- ci.yaml: Node 14 → 20, checkout/setup-node v2 → v4, removed
  legacy actions/cache step (setup-node v4 handles caching when a
  lockfile exists; this repo gitignores yarn.lock so omitted)
- linter.yaml: Node 16 → 20, checkout v3 → v4, setup-node v2 → v4,
  reviewdog/action-eslint v1.16.1 → v1.33.0
- cd.yml: same bumps applied preventatively (would break on master
  after this branch merges)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Intl.DateTimeFormat output for pt-BR with dateStyle: full and
timeStyle: long started including the "às" connector word in newer
ICU versions (Node >= 18). The CI bump from Node 14 to Node 20 in
this branch surfaced the divergence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@acassiovilasboas
Copy link
Copy Markdown

@claude

danimuller20
danimuller20 previously approved these changes May 7, 2026
Copy link
Copy Markdown
Contributor

@danimuller20 danimuller20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eu não sei se foi feito, mas seria interessante atualizar a base de conhecimento

…appears

The previous logic only switched from CPF mask to CNPJ mask when the
stripped input crossed 11 characters. Since the CPF pattern uses the
digit-only `9` placeholder from vanilla-masker, letters typed before
that threshold were silently dropped — making it impossible to enter
an alphanumeric CNPJ progressively (e.g. `12A`, `12AB`, ...).

Detect any A-Z early and route to MASKS.CNPJ (`SS.SSS.SSS/SSSS-99`)
immediately, while keeping the length-based branch for purely numeric
input so retrocompatibility with CPF/CNPJ numérico is preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@FabioRolin FabioRolin merged commit 57ea5e3 into master May 8, 2026
2 checks passed
@FabioRolin FabioRolin deleted the feat/cnpj-alphanumeric-and-input-masks branch May 8, 2026 19:38
@FabioRolin FabioRolin self-assigned this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants