Skip to content

feat(cnpj): support the alphanumeric CNPJ format#67

Merged
AZagatti merged 1 commit into
mainfrom
feat/alphanumeric-cnpj
Jun 24, 2026
Merged

feat(cnpj): support the alphanumeric CNPJ format#67
AZagatti merged 1 commit into
mainfrom
feat/alphanumeric-cnpj

Conversation

@AZagatti

Copy link
Copy Markdown
Collaborator

Adds support for the new alphanumeric CNPJ format (12 uppercase alphanumeric positions + 2 numeric check digits) from Receita Federal, keeping the legacy numeric format fully working.

Background

This consolidates the three community PRs (#59, #60, #62). I checked each against the official Receita Federal reference implementation (Java/Python/TypeScript). The selected base is #62 (@JeanNesi) — the only one using the correct ASCII offset of 48 ('0'→0, 'A'→17). #59 used offset 55 ('A'→10), which produces wrong check digits; #60 was correct but more verbose (Portuguese identifiers, throw-based port).

Implementation

  • Each base character → charCodeAt(0) - 48 (per spec), check digits stay numeric: ^[A-Z\d]{12}\d{2}$.
  • Only mask characters (., /, -) are stripped; lowercase letters and any other character are rejected (matches the official spec).
  • Module-scoped regex/weights and a generateChecksum helper that mirrors the existing validatePIS, for codebase consistency. The shared isRepeated util is untouched.

Tests

Full canonical test set from the official reference, including discriminating cases:

  • 00000000000191valid (all-zero base with a real DV), while 00000000000000 (zeroed) → invalid
  • lowercase rejected (12.ABc.345/01DE-35), letters in DV positions rejected (0000000000019L), invalid DV, disallowed characters, length checks
  • the 90.0xx.xxx series, ABCDEFGHIJKL80, 12.ABC.345/01DE-35

115 tests pass · Biome lint clean · tsc + build OK.

Co-authored with @JeanNesi (#62). Supersedes #59, #60, #62.

🤖 Generated with Claude Code

Validate the new Receita Federal alphanumeric CNPJ (12 uppercase
alphanumeric positions + 2 numeric check digits) while keeping the
legacy numeric format working.

The check-digit calculation maps each base character via its ASCII code
offset by 48 ('0' -> 0, 'A' -> 17 ... 'Z' -> 42), per the official spec,
and the 2 check digits remain numeric (regex ^[A-Z\d]{12}\d{2}$). Only
the mask characters (. / -) are stripped before validation.

Implementation selected from PR #62 (the only one matching the official
ASCII-48 offset), refined to match the codebase style (module-scoped
regex/weights, a generateChecksum helper mirroring validatePIS) and
covered with the full canonical test set from the Receita Federal
reference implementation, including the discriminating 00000000000191
(valid) and zeroed/lowercase/letter-in-DV rejection cases.

Co-authored-by: Jean Carlos Nesi <jean.nesi@nextfit.com.br>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AZagatti AZagatti merged commit 7d264ee into main Jun 24, 2026
2 checks passed
@AZagatti AZagatti deleted the feat/alphanumeric-cnpj branch June 24, 2026 02:45
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 91.492% (+0.08%) from 91.413% — feat/alphanumeric-cnpj into main

AZagatti added a commit that referenced this pull request Jun 24, 2026
Adds alphanumeric CNPJ validation (12 alphanumeric + 2 numeric DV) per the
Receita Federal spec, keeping legacy numeric support. Consolidates
#59/#60/#62; base implementation from #62 (@JeanNesi). Full canonical test
set; 115 tests pass.

Co-authored-by: Jean Carlos Nesi <102368879+JeanNesi@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants