Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions docs/pt-br/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,14 @@ generateCep(); // '92500000'

Busca o endereço de um CEP em vários provedores ao mesmo tempo e resolve com a primeira resposta bem-sucedida. O resultado é um `AddressInfo`: `cep`, `state`, `city`, `neighborhood` e `street`.

- **Opções** (`GetAddressInfoByCepOptions`): `providers` (`CepProvider[]`) lista os provedores a disputar (padrão `['viacep', 'brasilapi']`). `'widenet'` está descontinuado e fica fora da lista padrão.
- Aceita string ou número. Um número é preenchido com zeros à esquerda até 8 dígitos; um negativo ou fracionário é rejeitado com `GetAddressInfoByCepValidationError` antes de qualquer requisição.
- **Opções** (`GetAddressInfoByCepOptions`):
- `providers` (`CepProvider[]`) lista os provedores a disputar (padrão `['viacep', 'brasilapi']`). `'widenet'` está descontinuado e fica fora da lista padrão.
- `timeoutMs` (`number`) limita a busca inteira, tentativas incluídas (padrão: sem limite). Quando o tempo acaba, todas as requisições são abortadas e a chamada rejeita com `GetAddressInfoByCepServiceError`.
- `signal` (`AbortSignal`) cancela a busca; a chamada rejeita com `signal.reason`, como o `fetch`.
- Aceita string ou número. Uma string tem removido todo caractere que não é dígito (`'CEP 01310-100'` é `01310100`) e precisa sobrar com 8 dígitos. Um número é preenchido com zeros à esquerda até 8 dígitos, já que não carrega o zero inicial de um CEP de São Paulo, mas só a partir de `1000000` (`01000-000`, o menor CEP que os Correios atribuem). Um número menor, negativo ou fracionário é rejeitado com `GetAddressInfoByCepValidationError` antes de qualquer requisição.
- Repete falhas transitórias de rede por provedor.
- Rejeita com `GetAddressInfoByCepValidationError` quando o CEP é inválido ou `providers` não nomeia nenhum provedor conhecido, com `GetAddressInfoByCepNotFoundError` quando todos os provedores falharam e pelo menos um informou que o CEP é desconhecido, e com `GetAddressInfoByCepServiceError` quando todos os provedores falharam por outro motivo.
- Rejeita com `GetAddressInfoByCepValidationError` quando o CEP é inválido, `providers` não nomeia nenhum provedor conhecido ou `timeoutMs` não é um número finito positivo, com `GetAddressInfoByCepNotFoundError` quando todos os provedores falharam e pelo menos um informou que o CEP é desconhecido, e com `GetAddressInfoByCepServiceError` quando todos os provedores falharam por outro motivo.
- A BrasilAPI responde 404 tanto para um CEP desconhecido quanto quando os serviços por trás dela estão fora do ar, então o 404 dela só conta como "CEP desconhecido" quando nenhum outro provedor deixou de responder.
- Os três estendem `GetAddressInfoByCepError`, então um único `catch` cobre todos.

```javascript
Expand All @@ -290,6 +294,9 @@ const addressFromProviders = await getAddressInfoByCep('01310-100', {

// Usando número como entrada (será preenchido automaticamente com zeros à esquerda)
const addressFromNumber = await getAddressInfoByCep(1310100);

// Desistindo depois de 5 segundos
const addressWithinFiveSeconds = await getAddressInfoByCep('01310100', { timeoutMs: 5000 });
```

### getCepInfoByAddress
Expand Down Expand Up @@ -969,6 +976,7 @@ Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legis

Retorna o estado e a região a que um DDD brasileiro (código de área) pertence, dentre os 67 DDDs em uso no Plano Geral de Numeração da Anatel. Aceita string ou número inteiro não negativo.

- Uma string tem removido todo caractere que não é dígito, então `'(11)'`, `'0xx11'` e `'DDD 11'` são o DDD 11.
- Retorna um `AreaCodeInfo`: `areaCode`, `stateCode`, `stateName`, `regionCode`, `regionName` e `stateCodes`. Retorna `null` quando o DDD não está em uso.
- `stateCode` é o estado sede do DDD. Para os quatro DDDs que cruzam uma divisa (61, 42, 47 e 49) `stateCodes` lista também o outro estado, a sede primeiro.

Expand All @@ -985,6 +993,7 @@ getAreaCodeInfo('61');
// { areaCode: 61, stateCode: 'DF', stateName: 'Distrito Federal', regionCode: 'CO', regionName: 'Centro-Oeste', stateCodes: ['DF', 'GO'] }

getAreaCodeInfo('00'); // null
getAreaCodeInfo('(0xx11)'); // o mesmo que '11'
getAreaCodeInfo(-11); // null
getAreaCodeInfo(1.1); // null
```
Expand Down Expand Up @@ -1387,6 +1396,7 @@ Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilida

Busca um banco brasileiro pelo seu código de compensação (COMPE), a partir da lista de participantes do STR do Banco Central do Brasil. Aceita `string` ou `number`.

- Uma string tem removido todo caractere que não é dígito antes de o código ser completado para 3 dígitos.
- Retorna o `Bank` correspondente, ou `null` quando nenhum banco tem esse código.

```javascript
Expand All @@ -1401,7 +1411,9 @@ Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilida

### getBankByIspb

Busca um banco brasileiro pelo seu ISPB (Identificador do Sistema de Pagamentos Brasileiro), o código de 8 dígitos de todo participante do SPB. Aceita `string` ou `number`, com ou sem zeros à esquerda.
Busca um banco brasileiro pelo seu ISPB (Identificador do Sistema de Pagamentos Brasileiro), o código de 8 caracteres de todo participante do SPB. Aceita `string` ou `number`, com ou sem zeros à esquerda.

- Desde a Resolução BCB nº 585/2026 o ISPB pode ter letras, então uma string de 8 letras e dígitos é buscada como está, em maiúsculas ou minúsculas. Todo caractere que não é letra nem dígito é ignorado (`'00.000.000'` é `'00000000'`), e uma letra nunca é descartada (`'0000000A'` não é `'00000000'`).

- Retorna o `Bank` correspondente, ou `null` quando nenhum banco tem esse ISPB. A base só traz as instituições que também têm código COMPE.

Expand Down Expand Up @@ -1678,7 +1690,7 @@ Fonte: [Correios, Busca Faixa de CEP](https://buscacepinter.correios.com.br/app/
Retorna o estado brasileiro cujo código IBGE de 2 dígitos (`cUF`, o Código da Unidade da Federação) corresponde ao valor informado.

- É o código de UF do primeiro campo de uma chave de acesso de DF-e, a que `isValidNfeKey` cobre.
- Aceita string ou número inteiro não negativo.
- Aceita string ou número inteiro não negativo, com todo caractere que não é dígito removido da string (`'35/SP'` é `35`).
- Retorna `null` quando o código não corresponde a nenhum estado. Exporta o tipo `State`.

```javascript
Expand Down Expand Up @@ -1791,7 +1803,7 @@ Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)

Busca um município brasileiro pelo código IBGE de 7 dígitos.

- Aceita o código como string ou número inteiro não negativo.
- Aceita o código como string ou número inteiro não negativo, com todo caractere que não é dígito removido da string.
- Retorna `{ code, name, stateCode }` (`Municipality`), ou `null` quando o código não tem 7 dígitos ou não corresponde a nenhum município.

```javascript
Expand Down
24 changes: 18 additions & 6 deletions docs/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,14 @@ generateCep(); // '92500000'

Fetch the address of a CEP from several providers at once and resolve to the first successful answer. The result is an `AddressInfo`: `cep`, `state`, `city`, `neighborhood` and `street`.

- **Options** (`GetAddressInfoByCepOptions`): `providers` (`CepProvider[]`) lists the providers to race (default `['viacep', 'brasilapi']`). `'widenet'` is deprecated and left out of the default list.
- Accepts a string or a number. A number is left-padded with zeros to 8 digits; a negative or fractional one is rejected with `GetAddressInfoByCepValidationError` before any request is made.
- **Options** (`GetAddressInfoByCepOptions`):
- `providers` (`CepProvider[]`) lists the providers to race (default `['viacep', 'brasilapi']`). `'widenet'` is deprecated and left out of the default list.
- `timeoutMs` (`number`) bounds the whole lookup, retries included (default: no limit). When it runs out, every request is aborted and the call rejects with `GetAddressInfoByCepServiceError`.
- `signal` (`AbortSignal`) cancels the lookup; the call rejects with `signal.reason`, the same as `fetch`.
- Accepts a string or a number. A string has any non-digit characters stripped (`'CEP 01310-100'` is `01310100`) and has to leave 8 digits. A number is left-padded with zeros to 8 digits, since it cannot carry the leading zero of a São Paulo CEP, but only from `1000000` (`01000-000`, the lowest CEP the Correios assign) up. A smaller, negative or fractional number is rejected with `GetAddressInfoByCepValidationError` before any request is made.
- Retries transient network failures per provider.
- Rejects with `GetAddressInfoByCepValidationError` when the CEP is invalid or `providers` names no known provider, with `GetAddressInfoByCepNotFoundError` when every provider failed and at least one reported the CEP as unknown, and with `GetAddressInfoByCepServiceError` when every provider failed for another reason.
- Rejects with `GetAddressInfoByCepValidationError` when the CEP is invalid, `providers` names no known provider or `timeoutMs` is not a positive finite number, with `GetAddressInfoByCepNotFoundError` when every provider failed and at least one reported the CEP as unknown, and with `GetAddressInfoByCepServiceError` when every provider failed for another reason.
- BrasilAPI answers 404 both for an unknown CEP and when the services behind it are down, so its 404 only counts as "unknown CEP" when no other provider failed to answer.
- All three extend `GetAddressInfoByCepError`, so one `catch` covers them.

```javascript
Expand All @@ -290,6 +294,9 @@ const addressFromProviders = await getAddressInfoByCep('01310-100', {

// Using number input (will be padded automatically)
const addressFromNumber = await getAddressInfoByCep(1310100);

// Giving up after 5 seconds
const addressWithinFiveSeconds = await getAddressInfoByCep('01310100', { timeoutMs: 5000 });
```

### getCepInfoByAddress
Expand Down Expand Up @@ -969,6 +976,7 @@ Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legi

Get the state and region a Brazilian DDD (area code) belongs to, out of the 67 DDDs in use under the Anatel Plano Geral de Numeração. Accepts a string or a non-negative integer.

- A string has any non-digit characters stripped, so `'(11)'`, `'0xx11'` and `'DDD 11'` are the DDD 11.
- Returns an `AreaCodeInfo`: `areaCode`, `stateCode`, `stateName`, `regionCode`, `regionName` and `stateCodes`. Returns `null` when the DDD is not in use.
- `stateCode` is the state the DDD is seated in. For the four DDDs that straddle a border (61, 42, 47 and 49) `stateCodes` also lists the other state, the seat first.

Expand All @@ -985,6 +993,7 @@ getAreaCodeInfo('61');
// { areaCode: 61, stateCode: 'DF', stateName: 'Distrito Federal', regionCode: 'CO', regionName: 'Centro-Oeste', stateCodes: ['DF', 'GO'] }

getAreaCodeInfo('00'); // null
getAreaCodeInfo('(0xx11)'); // the same as '11'
getAreaCodeInfo(-11); // null
getAreaCodeInfo(1.1); // null
```
Expand Down Expand Up @@ -1387,6 +1396,7 @@ Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinan

Look a Brazilian bank up by its compensation code (COMPE), from the Banco Central do Brasil STR participants list. Accepts a `string` or a `number`.

- A string has any non-digit characters stripped before the code is padded to 3 digits.
- Returns the matching `Bank`, or `null` when no bank has that code.

```javascript
Expand All @@ -1401,7 +1411,9 @@ Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinan

### getBankByIspb

Look a Brazilian bank up by its ISPB (Identificador do Sistema de Pagamentos Brasileiro), the 8 digit code of every SPB participant. Accepts a `string` or a `number`, with or without leading zeros.
Look a Brazilian bank up by its ISPB (Identificador do Sistema de Pagamentos Brasileiro), the 8 character code of every SPB participant. Accepts a `string` or a `number`, with or without leading zeros.

- Since Resolução BCB nº 585/2026 an ISPB may hold letters, so a string of 8 letters and digits is looked up as it is, in upper or lower case. Any character that is neither a letter nor a digit is ignored (`'00.000.000'` is `'00000000'`), and a letter is never stripped (`'0000000A'` is not `'00000000'`).

- Returns the matching `Bank`, or `null` when no bank has that ISPB. The base only carries institutions that also have a COMPE code.

Expand Down Expand Up @@ -1678,7 +1690,7 @@ Source: [Correios, Busca Faixa de CEP](https://buscacepinter.correios.com.br/app
Get the Brazilian state whose 2-digit IBGE code (`cUF`, the Código da Unidade da Federação) matches the given value.

- This is the UF code in the first field of a DF-e access key (chave de acesso), the one `isValidNfeKey` covers.
- Accepts a string or a non-negative integer.
- Accepts a string or a non-negative integer, with any non-digit characters of a string stripped (`'35/SP'` is `35`).
- Returns `null` when the code matches no state. Exports the `State` type.

```javascript
Expand Down Expand Up @@ -1791,7 +1803,7 @@ Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades

Look up a Brazilian municipality by its 7-digit IBGE code.

- Accepts the code as a string or a non-negative integer.
- Accepts the code as a string or a non-negative integer, with any non-digit characters of a string stripped.
- Returns `{ code, name, stateCode }` (`Municipality`), or `null` when the code is not 7 digits long or matches no municipality.

```javascript
Expand Down
45 changes: 45 additions & 0 deletions src/_internals/read-lookup-digits/read-lookup-digits.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, test } from "../test/runtime";
import { readLookupDigits } from "./read-lookup-digits";

describe("readLookupDigits", () => {
test("should read a string of digits as it is", () => {
expect(readLookupDigits("3550308")).toBe("3550308");
expect(readLookupDigits("001")).toBe("001");
});

test("should drop whitespace and hyphens", () => {
expect(readLookupDigits(" 355-030-8 ")).toBe("3550308");
expect(readLookupDigits("0-01")).toBe("001");
expect(readLookupDigits("11\t")).toBe("11");
});

test("should read a non-negative integer number", () => {
expect(readLookupDigits(0)).toBe("0");
expect(readLookupDigits(3_550_308)).toBe("3550308");
});

test("should strip any non-digit character of a string, as up to 2.4.0", () => {
expect(readLookupDigits("(0xx11)")).toBe("011");
expect(readLookupDigits("DDD 11")).toBe("11");
expect(readLookupDigits("R$ 35")).toBe("35");
expect(readLookupDigits("35/SP")).toBe("35");
});

test("should return null for a string with no digit", () => {
expect(readLookupDigits("DDD")).toBeNull();
expect(readLookupDigits("")).toBeNull();
});

test("should reject a string with no digit left", () => {
expect(readLookupDigits("")).toBeNull();
expect(readLookupDigits(" - ")).toBeNull();
});

test("should reject a negative, fractional or unsafe number and a non-code value", () => {
expect(readLookupDigits(-11)).toBeNull();
expect(readLookupDigits(1.1)).toBeNull();
expect(readLookupDigits(2 ** 53)).toBeNull();
expect(readLookupDigits(null)).toBeNull();
expect(readLookupDigits(["11"])).toBeNull();
});
});
32 changes: 32 additions & 0 deletions src/_internals/read-lookup-digits/read-lookup-digits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { isLookupCode } from "../is-lookup-code/is-lookup-code";
import { sanitizeToDigits } from "../sanitize-to-digits/sanitize-to-digits";

/**
* Reads the digits of a lookup code, or `null` when the value is not a code at all.
*
* A number is read when `isLookupCode` accepts it, a non-negative safe integer, since a sign or
* a decimal point would otherwise be read as part of a code the caller never wrote. A string has
* every character that is not a digit stripped, as up to 2.4.0 (the documented contract of the
* lookups), so a masked or labelled code such as `"(0xx11)"`, `"35/SP"` or `"00.000.000"` is
* read by its digits.
*
* @param {unknown} value - The value to read.
* @returns {string|null} The digits of the code, or `null` when the value is not a number
* `isLookupCode` accepts or a string, or when no digit is left.
*
* @example
* ```typescript
* readLookupDigits(" 355-030-8 "); // "3550308"
* readLookupDigits(3550308); // "3550308"
* readLookupDigits("(0xx11)"); // "011"
* readLookupDigits(" - "); // null
* readLookupDigits(-11); // null
* ```
*/
export const readLookupDigits = (value: unknown): string | null => {
if (!isLookupCode(value)) return null;

const digits = sanitizeToDigits(value);

return digits === "" ? null : digits;
};
Loading
Loading