npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@br-geo-kit/address

v1.0.0

Published

Parse, format and validate Brazilian postal addresses

Readme

@br-geo-kit/address

Parse, render and validate a Brazilian postal address. Pure, offline, no dependencies beyond the kit.

pnpm add @br-geo-kit/address

Parsing a street line

Brazilian addresses are written logradouro, número, complemento, but the separators are not reliable: the comma before the number is often missing, the complement is sometimes introduced with a dash, and a building may be s/n.

import { parseStreetLine } from '@br-geo-kit/address'

parseStreetLine('Av. Paulista, 1578 - apto 42')
// { street: 'Avenida Paulista', type: 'Avenida', name: 'Paulista',
//   number: '1578', complement: 'apto 42', withoutNumber: false }

parseStreetLine('Rua das Flores 123')      // number: '123'
parseStreetLine('Rua XV de Novembro, s/n') // number: null, withoutNumber: true
parseStreetLine('Rodovia BR 101')          // the 101 belongs to the road

Abbreviations are expanded — Av., av, AVENIDA all become Avenida — because the same street arrives written four ways across four systems, and a lookup keyed on the raw string finds none of them.

withoutNumber is not the same as number === null. The first means the line said "no number" outright; the second means it did not mention one. A shipping form needs to tell a complete address from an incomplete one.

It never invents a number and never corrects spelling. Guessing that Paulsta meant Paulista is how a parcel ends up on the wrong street with nobody having approved it.


Rendering

The order is fixed by the Correios, not a matter of taste.

import { formatAddress, formatAddressLines } from '@br-geo-kit/address'

formatAddress(address)
// 'Avenida Paulista, 1578, apto 42, Bela Vista, São Paulo - SP, 01310-100'

formatAddressLines(address)
// ['Avenida Paulista, 1578, apto 42', 'Bela Vista', 'São Paulo - SP', '01310-100']

formatAddressLine(address)   // the one-line form a delivery app shows

Missing parts are dropped, never rendered as null or as an empty segment with stray punctuation around it. A CEP único with no street comes out as Porto Velho - RO, 76800-000, not , , Porto Velho - RO, 76800-000.


Validating

import { validateAddress, isValidAddress } from '@br-geo-kit/address'

validateAddress(address)
// [] — nothing wrong

validateAddress({ cep: '123', city: '', state: 'XX' })
// [ { field: 'cep', code: 'malformed', message: '...' },
//   { field: 'city', code: 'required', ... },
//   { field: 'state', code: 'malformed', ... } ]

Returns every issue, not the first — a form that reveals one problem per submission is a form people abandon. And returns them rather than throwing, because a failed validation is an expected outcome.

Two defaults that look wrong and are not:

  • A street is not required. Roughly 1 200 municipalities are addressed by a single CEP with no street. Requiring one rejects their residents. Turn it on with { requireStreet: true }.
  • A number is not required. A CEP lookup never returns one, so validating a freshly-resolved address would report every one of them as invalid. Turn it on with { requireNumber: true } when checking what a user submitted.

This validates shape, not existence. See API conventions for the three levels of "valid".


Also here

Re-exported from @br-geo-kit/core so a form needs one import:

import { maskCep, formatCep, normalizeCep, isWellFormedCep, toUF } from '@br-geo-kit/address'

maskCep('013101')      // '01310-1' — progressive, for an input field
formatCep('01310100')  // '01310-100'
normalizeCep(1310100)  // '01310100' — the leading zero a spreadsheet dropped

maskCep never returns null: a partial CEP is not an error while the user is mid-keystroke.

Licence

MIT