diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cb98fd889..04605aa57 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@
Thank you for your interest in contributing to Brazilian Utils! This project exists thanks to
[everyone who contributes](README.md#contributors), and we'd love your help solving the little
-day-to-day problems of building software for Brazilian businesses.
+day-to-day problems of building software for Brazil.
By participating in this project, you agree to abide by our
[Code of Conduct](CODE_OF_CONDUCT.md).
@@ -139,9 +139,14 @@ example `formatSomething`):
- `docs/utilities.md` (English)
- `docs/pt-br/utilities.md` (Portuguese translation)
- Follow the existing format: a `##` heading with the function name, a short description, and a
- `javascript` code block showing example input/output. Place the new section next to the other
- utilities in the same domain, keeping both files in the same order.
+ Follow the existing format: a `###` heading with the function name under the `##` family it
+ belongs to, one sentence saying what it does (`llms.txt` indexes that sentence), a few short
+ bullets for the options and the return rules, a `javascript` code block showing example
+ input/output, and a one-line `Source:` (`Fonte:` in Portuguese) with the official reference when
+ there is one. Do not repeat what the Conventions section at the top of the file already says
+ (nothing throws, masked input is accepted, generators use `Math.random()`); the JSDoc is the place
+ for every edge case, the reference is the place for what a caller needs. Keep both files in the
+ same order.
After editing `docs/getting-started.md` or `docs/utilities.md`, run `npm run build:llms` to
regenerate `docs/llms.txt` and `docs/llms-full.txt` (see [llms.txt](https://llmstxt.org/)) and
@@ -345,6 +350,17 @@ browser, with `_sidebar.md`, `_navbar.md` and `_coverpage.md` as its navigation.
`docs/llms-full.txt` keep their headings; run `npm run build:llms` after editing a page.
- Context7 indexes `docs/` as `/brazilian-utils/javascript`; `context7.json` says what it reads,
and `.github/workflows/context7.yml` asks for a refresh when the docs change on `main`.
+- The guide pages (`docs/guides/`, `docs/pt-br/guides/`) show how to use the package with React,
+ Vue, Angular and plain JavaScript. Their examples are complete: a `jsx` or `vue` block with a
+ default export, a `typescript` block whose default export is an `@Component` with the selector
+ `app-root`, or a full `html` document. `docs/run.js` (a docsify plugin loaded by `index.html`) puts a
+ Run button on those blocks and runs them in a sandboxed iframe, compiling JSX with sucrase, a
+ single-file component with `@vue/compiler-sfc` and an Angular component with Babel, each fetched
+ from jsdelivr when a button is first clicked, with an import map that resolves `react`, `vue`,
+ `@angular/*`, `zod`, `valibot` and the package itself to jsdelivr, at the versions pinned at the
+ top of `run.js`.
+ A new example only needs to follow one of those shapes; a fragment (no default export, no
+ ``) gets no button. `window.$docsify.run` overrides the CDN URLs when testing offline.
To preview the site, point a static file server that resolves `/page` to `page.html`, the way
GitHub Pages does, at `docs/`.
@@ -467,8 +483,8 @@ the commit messages.
responses as untrusted. A workflow change keeps actions pinned by SHA, permissions minimal and
secrets away from pull request code. A new development dependency needs a reason, a maintained
upstream and a license compatible with MIT.
-7. **Can the next person use it?** The JSDoc and both `docs/utilities.md` files describe what the
- code does, edge cases included, with an example that is true; the commit message has the right
+7. **Can the next person use it?** The JSDoc describes what the code does, edge cases included,
+ both `docs/utilities.md` files describe what a caller needs, with an example that is true; the commit message has the right
Conventional Commit type, because the changelog and the version are computed from it.
**Automated pull requests** get the same review with a narrower focus: a Dependabot bump is read
diff --git a/README.md b/README.md
index abb4df232..59853d24e 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-
Utils library for Brazilian-specific businesses.
+
Utilities for Brazilian data: CPF, CNPJ, CEP, boleto, Pix, holidays and more.
[📖 Documentation](https://brazilian-utils.com.br/getting-started)
@@ -29,46 +29,24 @@
# Getting Started
-Brazilian Utils is a library focused on solving problems that we face daily in the development of applications for the Brazilian business.
+Brazilian Utils is a zero-dependency library of small utilities for the day-to-day problems of building software for Brazil: validating, formatting, parsing and generating CPF, CNPJ, CEP, boleto, Pix, phone numbers, holidays and more.
## Why Brazilian Utils
- **Zero runtime dependencies.** Nothing else lands in your `node_modules` or in your bundle.
-- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped); every util is also its own subpath entry (`@brazilian-utils/brazilian-utils/get-cities`) for the heavy ones.
-- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, tested in CI on every one of them.
-- **Written in TypeScript.** Types ship with the package; the public API is tracked by an API report so nothing changes silently.
-- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements (`@see` in the docs), and the test suite is mutation-tested, not just covered.
+- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped). Every util is also its own subpath entry, so the heavy ones can be lazy-loaded.
+- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, all tested in CI.
+- **Written in TypeScript.** Types ship with the package, and an API report tracks the public API so nothing changes silently.
+- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements, and the test suite is mutation-tested, not just covered.
- **Documented in English and Portuguese**, with an `llms.txt` for AI assistants.
## Installation
-You can install **Brazilian Utils** in a few ways:
-
-as npm package:
-
-```bash
-npm install --save @brazilian-utils/brazilian-utils
-```
-
-with yarn package manager:
-
-```bash
-yarn add @brazilian-utils/brazilian-utils
-```
-
-with pnpm:
-
-```bash
-pnpm add @brazilian-utils/brazilian-utils
-```
-
-with bun:
-
```bash
-bun add @brazilian-utils/brazilian-utils
+npm install @brazilian-utils/brazilian-utils
```
-or `
@@ -76,9 +54,9 @@ or `
+
+
+
+
+
+
+
diff --git a/docs/_coverpage.md b/docs/_coverpage.md
index 6d6fc24b2..1aa2343f8 100644
--- a/docs/_coverpage.md
+++ b/docs/_coverpage.md
@@ -1,6 +1,6 @@
-> Utils library for Brazilian-specific businesses.
+> Utilities for Brazilian data: CPF, CNPJ, CEP, boleto, Pix, holidays and more.
- Zero runtime dependencies
- Tree-shakeable, one import per util
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index 478e19202..d4698a88e 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -1,3 +1,8 @@
* [Getting Started](getting-started.md)
* [Utilities](utilities.md)
+* Guides
+ * [React](guides/react.md)
+ * [Vue](guides/vue.md)
+ * [Angular](guides/angular.md)
+ * [Plain JavaScript](guides/vanilla.md)
* [Migration v1 to v2](migration-v1-to-v2.md)
diff --git a/docs/getting-started.html b/docs/getting-started.html
index aad70064a..95c3cee10 100644
--- a/docs/getting-started.html
+++ b/docs/getting-started.html
@@ -4,7 +4,7 @@
Getting Started · Brazilian Utils
-
+
@@ -32,7 +32,7 @@
-
+
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/getting-started.md b/docs/getting-started.md
index b88032c2d..afa646011 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -1,49 +1,27 @@
---
title: "Getting Started"
-description: "Install Brazilian Utils, the zero-dependency utils library for Brazilian businesses, and learn how to import a util, which runtimes are supported and how the bundle size behaves."
+description: "Install Brazilian Utils, the zero-dependency library of utilities for Brazilian data, import a util, check the supported runtimes and keep your bundle small."
keywords: ["Brazilian Utils", "install", "npm", "tree-shaking", "bundle size", "subpath imports", "Node.js", "Bun", "Deno", "browser", "AI assistants", "Context7"]
---
-Brazilian Utils is a library focused on solving problems that we face daily in the development of applications for the Brazilian business.
+Brazilian Utils is a zero-dependency library of small utilities for the day-to-day problems of building software for Brazil: validating, formatting, parsing and generating CPF, CNPJ, CEP, boleto, Pix, phone numbers, holidays and more.
## Why Brazilian Utils
- **Zero runtime dependencies.** Nothing else lands in your `node_modules` or in your bundle.
-- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped); every util is also its own subpath entry (`@brazilian-utils/brazilian-utils/get-cities`) for the heavy ones.
-- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, tested in CI on every one of them.
-- **Written in TypeScript.** Types ship with the package; the public API is tracked by an API report so nothing changes silently.
-- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements (`@see` in the docs), and the test suite is mutation-tested, not just covered.
+- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped). Every util is also its own subpath entry, so the heavy ones can be lazy-loaded.
+- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, all tested in CI.
+- **Written in TypeScript.** Types ship with the package, and an API report tracks the public API so nothing changes silently.
+- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements, and the test suite is mutation-tested, not just covered.
- **Documented in English and Portuguese**, with an `llms.txt` for AI assistants.
## Installation
-You can install **Brazilian Utils** in a few ways:
-
-as npm package:
-
-```bash
-npm install --save @brazilian-utils/brazilian-utils
-```
-
-with yarn package manager:
-
```bash
-yarn add @brazilian-utils/brazilian-utils
+npm install @brazilian-utils/brazilian-utils
```
-with pnpm:
-
-```bash
-pnpm add @brazilian-utils/brazilian-utils
-```
-
-with bun:
-
-```bash
-bun add @brazilian-utils/brazilian-utils
-```
-
-or `
@@ -51,11 +29,16 @@ or `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/angular.md b/docs/guides/angular.md
new file mode 100644
index 000000000..1e19fd122
--- /dev/null
+++ b/docs/guides/angular.md
@@ -0,0 +1,382 @@
+---
+title: "Using with Angular"
+description: "Validate and format Brazilian documents in Angular forms: signals, input masks, reactive forms with custom validators, and form schemas with zod or valibot, with runnable examples."
+keywords: ["Angular", "signals", "reactive forms", "validators", "input mask", "zod", "valibot", "CPF", "CNPJ", "CEP", "phone"]
+---
+
+Brazilian Utils has no Angular code in it: every function takes a value and returns a value, so it works in a signal, a validator or a pipe. This page shows the patterns that come up in most apps, as standalone components with signals (Angular 22, zoneless). Every example runs in your browser: click **Run** under the code.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validate as the user types
+
+Keep the input in a signal and derive the validity with `computed`. The validator accepts the value with or without its mask, so there is nothing to strip first.
+
+```typescript
+import { Component, computed, signal } from '@angular/core';
+import { isValidCpf } from '@brazilian-utils/brazilian-utils';
+
+@Component({
+ selector: 'app-root',
+ template: `
+
+ CPF
+
+ @if (cpf()) {
+ {{ valid() ? 'Valid CPF' : 'Invalid CPF' }}
+ }
+
+ `,
+})
+export default class CpfField {
+ cpf = signal('');
+ valid = computed(() => isValidCpf(this.cpf()));
+}
+```
+
+## Format while typing (input mask)
+
+The `format*` functions mask a value as far as it goes, so writing the formatted value into the signal on every `input` event gives you an input mask with no extra library. Use `{ mask: 'nanp' }` for a phone with area code.
+
+```typescript
+import { Component, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { formatCep, formatCnpj, formatCpf, formatPhone } from '@brazilian-utils/brazilian-utils';
+
+const masks = {
+ cpf: formatCpf,
+ cnpj: formatCnpj,
+ phone: (value: string) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+type Field = keyof typeof masks;
+
+@Component({
+ selector: 'app-root',
+ imports: [JsonPipe],
+ template: `
+
+ `,
+})
+export default class MaskedInputs {
+ fields: { name: Field; label: string; placeholder: string }[] = [
+ { name: 'cpf', label: 'CPF', placeholder: '000.000.000-00' },
+ { name: 'cnpj', label: 'CNPJ', placeholder: '00.000.000/0000-00' },
+ { name: 'phone', label: 'Phone', placeholder: '(00) 00000-0000' },
+ { name: 'cep', label: 'CEP', placeholder: '00000-000' },
+ ];
+
+ values = signal
>({ cpf: '', cnpj: '', phone: '', cep: '' });
+
+ update(name: Field, event: Event) {
+ const value = masks[name]((event.target as HTMLInputElement).value);
+ this.values.update((current) => ({ ...current, [name]: value }));
+ }
+}
+```
+
+## Validate a reactive form
+
+A validator is a function from a control to an error object, so any `isValid*` becomes one in a line. The masks go on the `input` event, and `parse*` strips them before the data leaves the form.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { AbstractControl, NonNullableFormBuilder, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const validator = (check: (value: string) => boolean) =>
+ (control: AbstractControl): ValidationErrors | null => (check(control.value) ? null : { invalid: true });
+
+const masks: Partial string>> = {
+ cpf: formatCpf,
+ phone: (value) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+const messages = { name: 'Name is required', cpf: 'Invalid CPF', phone: 'Invalid phone', cep: 'Invalid CEP' };
+
+type Field = keyof typeof messages;
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class SignupForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['name', 'cpf', 'phone', 'cep'];
+
+ form = this.fb.group({
+ name: ['', [Validators.required, Validators.minLength(2)]],
+ cpf: ['', validator(isValidCpf)],
+ phone: ['', validator((value) => isValidPhone(value))],
+ cep: ['', validator(isValidCep)],
+ });
+
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ const format = masks[name];
+ if (format) this.form.controls[name].setValue(format((event.target as HTMLInputElement).value));
+ }
+
+ error(name: Field) {
+ const control = this.form.controls[name];
+ return control.touched && control.invalid ? messages[name] : '';
+ }
+
+ submit() {
+ this.form.markAllAsTouched();
+ if (this.form.invalid) {
+ this.data.set(null);
+ return;
+ }
+ const { name, cpf, phone, cep } = this.form.getRawValue();
+ this.data.set({ name, cpf: parseCpf(cpf), phone: parsePhone(phone), cep: parseCep(cep) });
+ }
+}
+```
+
+## Validate a form with zod
+
+Put the validator in a `refine` and the parser in a `transform`: the schema rejects a bad document with your message and hands you the digits of a good one, ready for the API. The form itself stays plain; zod runs on submit.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';
+import { z } from 'zod';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = z.object({
+ name: z.string().min(2, 'Name is required'),
+ cpf: z.string().refine(isValidCpf, 'Invalid CPF').transform(parseCpf),
+ phone: z.string().refine((value) => isValidPhone(value), 'Invalid phone').transform(parsePhone),
+ cep: z.string().refine(isValidCep, 'Invalid CEP').transform(parseCep),
+});
+
+type Field = keyof z.infer;
+
+const masks: Partial string>> = {
+ cpf: formatCpf,
+ phone: (value) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class SignupForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['name', 'cpf', 'phone', 'cep'];
+ form = this.fb.group({ name: '', cpf: '', phone: '', cep: '' });
+ errors = signal>>({});
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ const format = masks[name];
+ if (format) this.form.controls[name].setValue(format((event.target as HTMLInputElement).value));
+ }
+
+ submit() {
+ const result = schema.safeParse(this.form.getRawValue());
+ if (!result.success) {
+ this.errors.set(Object.fromEntries(result.error.issues.map((issue) => [issue.path[0], issue.message])));
+ this.data.set(null);
+ return;
+ }
+ this.errors.set({});
+ this.data.set(result.data);
+ }
+}
+```
+
+## Validate a form with valibot
+
+The same idea in valibot: `check` for the validator, `transform` for the parser, `flatten` to read the messages by field.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';
+import * as v from 'valibot';
+import {
+ formatCnpj, formatCpf,
+ isValidCnpj, isValidCpf,
+ parseCnpj, parseCpf,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = v.object({
+ cpf: v.pipe(v.string(), v.check(isValidCpf, 'Invalid CPF'), v.transform(parseCpf)),
+ cnpj: v.pipe(v.string(), v.check((value) => isValidCnpj(value), 'Invalid CNPJ'), v.transform(parseCnpj)),
+});
+
+type Field = keyof v.InferInput;
+
+const masks: Record string> = { cpf: formatCpf, cnpj: formatCnpj };
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class CompanyForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['cpf', 'cnpj'];
+ form = this.fb.group({ cpf: '', cnpj: '' });
+ errors = signal>>({});
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ this.form.controls[name].setValue(masks[name]((event.target as HTMLInputElement).value));
+ }
+
+ submit() {
+ const result = v.safeParse(schema, this.form.getRawValue());
+ if (!result.success) {
+ const nested = v.flatten(result.issues).nested ?? {};
+ this.errors.set(Object.fromEntries(Object.entries(nested).map(([field, messages]) => [field, messages?.[0]])));
+ this.data.set(null);
+ return;
+ }
+ this.errors.set({});
+ this.data.set(result.output);
+ }
+}
+```
+
+## Format for display
+
+Store the digits, format in the template. Expose the functions you need as fields of the component (or wrap one in a pipe). `formatCpf` can hide the digits the way gov.br does, and `formatPhone` with `mask: 'auto'` picks the right pattern from the number itself.
+
+```typescript
+import { Component } from '@angular/core';
+import {
+ convertCurrencyToWords, formatCnpj, formatCpf, formatCurrency, formatPhone,
+} from '@brazilian-utils/brazilian-utils';
+
+@Component({
+ selector: 'app-root',
+ template: `
+
+ Customer
+ {{ order.customer }} ({{ formatCpf(order.cpf, { obfuscate: true }) }})
+ Company
+ {{ order.company }}, CNPJ {{ formatCnpj(order.cnpj) }}
+ Phone
+ {{ formatPhone(order.phone, { mask: 'auto' }) }}
+ Total
+
+ {{ formatCurrency(order.total, { symbol: true }) }}
+
+ {{ convertCurrencyToWords(order.total) }}
+
+
+ `,
+})
+export default class Receipt {
+ order = {
+ customer: 'Maria da Silva',
+ cpf: '12345678909',
+ company: 'ACME LTDA',
+ cnpj: '12345678000195',
+ phone: '11987654321',
+ total: 1234.56,
+ };
+
+ protected readonly formatCpf = formatCpf;
+ protected readonly formatCnpj = formatCnpj;
+ protected readonly formatPhone = formatPhone;
+ protected readonly formatCurrency = formatCurrency;
+ protected readonly convertCurrencyToWords = convertCurrencyToWords;
+}
+```
+
+## Where to go next
+
+- The [utilities reference](utilities.md) lists every function with its options.
+- The same patterns for [React](guides/react.md), [Vue](guides/vue.md) and [plain JavaScript](guides/vanilla.md).
+- Heavy utils such as `getMunicipalities` deserve a lazy import; see [Bundle size](getting-started.md#bundle-size).
diff --git a/docs/guides/react.html b/docs/guides/react.html
new file mode 100644
index 000000000..454d43493
--- /dev/null
+++ b/docs/guides/react.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Using with React · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/react.md b/docs/guides/react.md
new file mode 100644
index 000000000..c9ac3e890
--- /dev/null
+++ b/docs/guides/react.md
@@ -0,0 +1,245 @@
+---
+title: "Using with React"
+description: "Validate and format Brazilian documents in React forms: input masks, validation as the user types, and form schemas with zod or valibot, with runnable examples."
+keywords: ["React", "form", "input mask", "zod", "valibot", "react-hook-form", "CPF", "CNPJ", "CEP", "phone"]
+---
+
+Brazilian Utils has no React code in it: every function takes a value and returns a value, so it plugs into any component, hook or form library. This page shows the patterns that come up in most apps. Every example runs in your browser: click **Run** under the code.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validate as the user types
+
+Keep the input in state and ask the validator on every render. The validator accepts the value with or without its mask, so there is nothing to strip first.
+
+```jsx
+import { useState } from 'react';
+import { isValidCpf } from '@brazilian-utils/brazilian-utils';
+
+export default function CpfField() {
+ const [cpf, setCpf] = useState('');
+ const valid = isValidCpf(cpf);
+
+ return (
+
+ CPF
+ setCpf(event.target.value)}
+ placeholder="000.000.000-00"
+ inputMode="numeric"
+ />
+ {cpf && {valid ? 'Valid CPF' : 'Invalid CPF'} }
+
+ );
+}
+```
+
+## Format while typing (input mask)
+
+The `format*` functions mask a value as far as it goes, so passing the raw input through one of them on every change gives you an input mask with no extra library. Use `{ mask: 'nanp' }` for a phone with area code.
+
+```jsx
+import { useState } from 'react';
+import { formatCep, formatCnpj, formatCpf, formatPhone } from '@brazilian-utils/brazilian-utils';
+
+const fields = [
+ { name: 'cpf', label: 'CPF', format: formatCpf, placeholder: '000.000.000-00' },
+ { name: 'cnpj', label: 'CNPJ', format: formatCnpj, placeholder: '00.000.000/0000-00' },
+ { name: 'phone', label: 'Phone', format: (value) => formatPhone(value, { mask: 'nanp' }), placeholder: '(00) 00000-0000' },
+ { name: 'cep', label: 'CEP', format: formatCep, placeholder: '00000-000' },
+];
+
+export default function MaskedInputs() {
+ const [values, setValues] = useState({ cpf: '', cnpj: '', phone: '', cep: '' });
+
+ return (
+
+ );
+}
+```
+
+## Validate a form with zod
+
+Put the validator in a `refine` and the parser in a `transform`: the schema rejects a bad document with your message and hands you the digits of a good one, ready for the API.
+
+```jsx
+import { useState } from 'react';
+import { z } from 'zod';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = z.object({
+ name: z.string().min(2, 'Name is required'),
+ cpf: z.string().refine(isValidCpf, 'Invalid CPF').transform(parseCpf),
+ phone: z.string().refine((value) => isValidPhone(value), 'Invalid phone').transform(parsePhone),
+ cep: z.string().refine(isValidCep, 'Invalid CEP').transform(parseCep),
+});
+
+const masks = { cpf: formatCpf, phone: (value) => formatPhone(value, { mask: 'nanp' }), cep: formatCep };
+
+export default function SignupForm() {
+ const [values, setValues] = useState({ name: '', cpf: '', phone: '', cep: '' });
+ const [errors, setErrors] = useState({});
+ const [data, setData] = useState(null);
+
+ function change(event) {
+ const { name, value } = event.target;
+ setValues({ ...values, [name]: masks[name] ? masks[name](value) : value });
+ }
+
+ function submit(event) {
+ event.preventDefault();
+ const result = schema.safeParse(values);
+ if (!result.success) {
+ setErrors(Object.fromEntries(result.error.issues.map((issue) => [issue.path[0], issue.message])));
+ setData(null);
+ return;
+ }
+ setErrors({});
+ setData(result.data);
+ }
+
+ return (
+
+ );
+}
+```
+
+With react-hook-form, the same schema goes into the resolver and the fields are registered as usual:
+
+```jsx
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+
+const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(schema) });
+```
+
+## Validate a form with valibot
+
+The same idea in valibot: `check` for the validator, `transform` for the parser, `flatten` to read the messages by field.
+
+```jsx
+import { useState } from 'react';
+import * as v from 'valibot';
+import {
+ formatCnpj, formatCpf,
+ isValidCnpj, isValidCpf,
+ parseCnpj, parseCpf,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = v.object({
+ cpf: v.pipe(v.string(), v.check(isValidCpf, 'Invalid CPF'), v.transform(parseCpf)),
+ cnpj: v.pipe(v.string(), v.check((value) => isValidCnpj(value), 'Invalid CNPJ'), v.transform(parseCnpj)),
+});
+
+const masks = { cpf: formatCpf, cnpj: formatCnpj };
+
+export default function CompanyForm() {
+ const [values, setValues] = useState({ cpf: '', cnpj: '' });
+ const [errors, setErrors] = useState({});
+ const [data, setData] = useState(null);
+
+ function submit(event) {
+ event.preventDefault();
+ const result = v.safeParse(schema, values);
+ if (!result.success) {
+ const nested = v.flatten(result.issues).nested ?? {};
+ setErrors(Object.fromEntries(Object.entries(nested).map(([field, messages]) => [field, messages[0]])));
+ setData(null);
+ return;
+ }
+ setErrors({});
+ setData(result.output);
+ }
+
+ return (
+
+ );
+}
+```
+
+## Format for display
+
+Store the digits, format on render. `formatCpf` can hide the digits the way gov.br does, and `formatPhone` with `mask: 'auto'` picks the right pattern from the number itself.
+
+```jsx
+import {
+ convertCurrencyToWords, formatCnpj, formatCpf, formatCurrency, formatPhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const order = {
+ customer: 'Maria da Silva',
+ cpf: '12345678909',
+ company: 'ACME LTDA',
+ cnpj: '12345678000195',
+ phone: '11987654321',
+ total: 1234.56,
+};
+
+export default function Receipt() {
+ return (
+
+ Customer
+ {order.customer} ({formatCpf(order.cpf, { obfuscate: true })})
+ Company
+ {order.company}, CNPJ {formatCnpj(order.cnpj)}
+ Phone
+ {formatPhone(order.phone, { mask: 'auto' })}
+ Total
+
+ {formatCurrency(order.total, { symbol: true })}
+
+ {convertCurrencyToWords(order.total)}
+
+
+ );
+}
+```
+
+## Where to go next
+
+- The [utilities reference](utilities.md) lists every function with its options.
+- The same patterns for [Vue](guides/vue.md), [Angular](guides/angular.md) and [plain JavaScript](guides/vanilla.md).
+- Heavy utils such as `getMunicipalities` deserve a lazy import; see [Bundle size](getting-started.md#bundle-size).
diff --git a/docs/guides/vanilla.html b/docs/guides/vanilla.html
new file mode 100644
index 000000000..b19ffbb84
--- /dev/null
+++ b/docs/guides/vanilla.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Using with plain JavaScript · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/vanilla.md b/docs/guides/vanilla.md
new file mode 100644
index 000000000..0768294a1
--- /dev/null
+++ b/docs/guides/vanilla.md
@@ -0,0 +1,261 @@
+---
+title: "Using with plain JavaScript"
+description: "Validate and format Brazilian documents with no framework: input masks on a plain form, validation on submit, and form schemas with zod or valibot, with runnable examples."
+keywords: ["vanilla", "JavaScript", "form", "input mask", "zod", "valibot", "script tag", "UMD", "CPF", "CNPJ", "CEP", "phone"]
+---
+
+No framework needed: every function takes a value and returns a value. The examples on this page are complete HTML files that load the package from a CDN through an import map, so they run as they are, in the browser or in a file on your disk. Click **Run** under the code. With a bundler, drop the import map and `npm install @brazilian-utils/brazilian-utils`.
+
+## Load the package
+
+As an ES module, with an import map (what the examples below do):
+
+```html
+
+
+```
+
+Or as a classic script, which exposes the global `BrazilianUtils`:
+
+```html
+
+
+```
+
+## Validate as the user types
+
+Listen to `input` and ask the validator. It accepts the value with or without its mask, so there is nothing to strip first.
+
+```html
+
+
+
+
+ CPF
+
+
+
+
+
+
+
+
+```
+
+## Format while typing (input mask)
+
+The `format*` functions mask a value as far as it goes, so writing the formatted value back on every `input` event gives you an input mask with no extra library. Use `{ mask: 'nanp' }` for a phone with area code.
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+## Validate a form with zod
+
+Put the validator in a `refine` and the parser in a `transform`: the schema rejects a bad document with your message and hands you the digits of a good one, ready for the API.
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## Validate a form with valibot
+
+The same idea in valibot: `check` for the validator, `transform` for the parser, `flatten` to read the messages by field.
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## Format for display
+
+Store the digits, format when rendering. `formatCpf` can hide the digits the way gov.br does, and `formatPhone` with `mask: 'auto'` picks the right pattern from the number itself.
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+## Where to go next
+
+- The [utilities reference](utilities.md) lists every function with its options.
+- The same patterns for [React](guides/react.md), [Vue](guides/vue.md) and [Angular](guides/angular.md).
+- Heavy utils such as `getMunicipalities` deserve a lazy import; see [Bundle size](getting-started.md#bundle-size).
diff --git a/docs/guides/vue.html b/docs/guides/vue.html
new file mode 100644
index 000000000..8fb58caf0
--- /dev/null
+++ b/docs/guides/vue.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Using with Vue · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/vue.md b/docs/guides/vue.md
new file mode 100644
index 000000000..d5d80be5c
--- /dev/null
+++ b/docs/guides/vue.md
@@ -0,0 +1,226 @@
+---
+title: "Using with Vue"
+description: "Validate and format Brazilian documents in Vue forms: input masks with v-model, validation as the user types, and form schemas with zod or valibot, with runnable examples."
+keywords: ["Vue", "form", "v-model", "input mask", "zod", "valibot", "vee-validate", "CPF", "CNPJ", "CEP", "phone"]
+---
+
+Brazilian Utils has no Vue code in it: every function takes a value and returns a value, so it plugs into a `ref`, a `computed` or any form library. This page shows the patterns that come up in most apps, as single-file components. Every example runs in your browser: click **Run** under the code.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validate as the user types
+
+Keep the input in a `ref` and derive the validity with `computed`. The validator accepts the value with or without its mask, so there is nothing to strip first.
+
+```vue
+
+
+
+
+ CPF
+
+ {{ valid ? 'Valid CPF' : 'Invalid CPF' }}
+
+
+```
+
+## Format while typing (input mask)
+
+A writable `computed` turns any `format*` function into a `v-model` mask: the setter formats what was typed, the getter returns it. Use `{ mask: 'nanp' }` for a phone with area code.
+
+```vue
+
+
+
+
+
+```
+
+## Validate a form with zod
+
+Put the validator in a `refine` and the parser in a `transform`: the schema rejects a bad document with your message and hands you the digits of a good one, ready for the API.
+
+```vue
+
+
+
+
+
+```
+
+With vee-validate, the same schema goes through `toTypedSchema` and the fields are bound with `useField` or ``:
+
+```javascript
+import { useForm } from 'vee-validate';
+import { toTypedSchema } from '@vee-validate/zod';
+
+const { handleSubmit, errors } = useForm({ validationSchema: toTypedSchema(schema) });
+```
+
+## Validate a form with valibot
+
+The same idea in valibot: `check` for the validator, `transform` for the parser, `flatten` to read the messages by field.
+
+```vue
+
+
+
+
+
+```
+
+## Format for display
+
+Store the digits, format in the template. `formatCpf` can hide the digits the way gov.br does, and `formatPhone` with `mask: 'auto'` picks the right pattern from the number itself.
+
+```vue
+
+
+
+
+ Customer
+ {{ order.customer }} ({{ formatCpf(order.cpf, { obfuscate: true }) }})
+ Company
+ {{ order.company }}, CNPJ {{ formatCnpj(order.cnpj) }}
+ Phone
+ {{ formatPhone(order.phone, { mask: 'auto' }) }}
+ Total
+
+ {{ formatCurrency(order.total, { symbol: true }) }}
+
+ {{ convertCurrencyToWords(order.total) }}
+
+
+
+```
+
+## Where to go next
+
+- The [utilities reference](utilities.md) lists every function with its options.
+- The same patterns for [React](guides/react.md), [Angular](guides/angular.md) and [plain JavaScript](guides/vanilla.md).
+- Heavy utils such as `getMunicipalities` deserve a lazy import; see [Bundle size](getting-started.md#bundle-size).
diff --git a/docs/index.html b/docs/index.html
index b42c1373e..3483bdc36 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -4,7 +4,7 @@
Brazilian Utils
-
+
@@ -31,7 +31,7 @@
-
+
@@ -49,14 +49,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -257,8 +257,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/llms-full.txt b/docs/llms-full.txt
index 11a71008d..2247e5e86 100644
--- a/docs/llms-full.txt
+++ b/docs/llms-full.txt
@@ -1,6 +1,6 @@
# Brazilian Utils
-> Brazilian Utils is a zero-dependency JavaScript/TypeScript library of small, focused utilities for the day-to-day problems of building software for Brazilian businesses. This file concatenates the full English documentation (getting started + utilities reference) in one Markdown document for LLM context loading.
+> Brazilian Utils is a zero-dependency JavaScript/TypeScript library of small, focused utilities for the day-to-day problems of building software for Brazil. This file concatenates the full English documentation (getting started + utilities reference) in one Markdown document for LLM context loading.
## Table of contents
@@ -153,46 +153,24 @@
## Getting Started
-Brazilian Utils is a library focused on solving problems that we face daily in the development of applications for the Brazilian business.
+Brazilian Utils is a zero-dependency library of small utilities for the day-to-day problems of building software for Brazil: validating, formatting, parsing and generating CPF, CNPJ, CEP, boleto, Pix, phone numbers, holidays and more.
### Why Brazilian Utils
- **Zero runtime dependencies.** Nothing else lands in your `node_modules` or in your bundle.
-- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped); every util is also its own subpath entry (`@brazilian-utils/brazilian-utils/get-cities`) for the heavy ones.
-- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, tested in CI on every one of them.
-- **Written in TypeScript.** Types ship with the package; the public API is tracked by an API report so nothing changes silently.
-- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements (`@see` in the docs), and the test suite is mutation-tested, not just covered.
+- **Tree-shakeable, down to the function.** `import { isValidCpf }` costs about 1.4 KB minified (0.8 KB gzipped). Every util is also its own subpath entry, so the heavy ones can be lazy-loaded.
+- **Runs everywhere.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno and evergreen browsers, all tested in CI.
+- **Written in TypeScript.** Types ship with the package, and an API report tracks the public API so nothing changes silently.
+- **Validated against the official rules.** Every validator cites the specification, law or dataset it implements, and the test suite is mutation-tested, not just covered.
- **Documented in English and Portuguese**, with an `llms.txt` for AI assistants.
### Installation
-You can install **Brazilian Utils** in a few ways:
-
-as npm package:
-
-```bash
-npm install --save @brazilian-utils/brazilian-utils
-```
-
-with yarn package manager:
-
-```bash
-yarn add @brazilian-utils/brazilian-utils
-```
-
-with pnpm:
-
-```bash
-pnpm add @brazilian-utils/brazilian-utils
-```
-
-with bun:
-
```bash
-bun add @brazilian-utils/brazilian-utils
+npm install @brazilian-utils/brazilian-utils
```
-or `
@@ -200,11 +178,16 @@ or `
+
+
+
+
+
+
+
diff --git a/docs/migration-v1-to-v2.md b/docs/migration-v1-to-v2.md
index 6222f8c12..524b20b51 100644
--- a/docs/migration-v1-to-v2.md
+++ b/docs/migration-v1-to-v2.md
@@ -4,149 +4,35 @@ description: "How to move a project from Brazilian Utils v1.x to v2: the renamed
keywords: ["migration", "v1", "v2", "deprecated", "renamed exports", "upgrade"]
---
-This guide will help you migrate from Brazilian Utils v1.x to v2.0.0.
+This guide covers moving a project from Brazilian Utils v1.x to v2.
-## TL;DR - Quick Migration
+## Summary
-**Good news!** v2.x maintains backward compatibility for most breaking changes:
+v2 renames every function to camelCase (`formatCPF` is now `formatCpf`) but keeps the v1 names as deprecated aliases, so most projects upgrade without changing code. TypeScript and your editor flag the old names. The aliases are removed in v3.0.0.
-✅ **You can upgrade to v2.x without changing your code** - old function names like `formatCPF`, `isValidCNPJ`, etc. still work
-⚠️ **You'll receive deprecation warnings** - encouraging you to migrate to the new names
-🗑️ **Old names will be removed in v3.0.0** - so migrate gradually
+Four v1 helpers were internal and have no alias. Replace them before upgrading:
-**However**, you must remove usage of these helper functions before upgrading:
-- `onlyNumbers` → use `string.replace(/\D/g, '')`
-- `isLastChar` → use `index === input.length - 1`
-- `generateChecksum` → now internal only
-- `generateRandomNumber` → now internal only
-
-## Improvements in v2.0.0
-
-Version 2.0.0 brings significant improvements in architecture, tooling, and developer experience:
-
-### 🎯 Better Tree Shaking
-
-The library now uses modern ES module exports with proper `exports` field in `package.json`, enabling better tree shaking in modern bundlers. You can import only what you need:
-
-```javascript
-// Only the functions you import will be included in your bundle
-import { isValidCpf, formatCpf } from '@brazilian-utils/brazilian-utils';
-```
-
-Since 2.4.0 every util is also its own subpath entry, so a bundler that does not tree-shake (or a
-plain `require`) still loads a single module, and the few heavy ones (`getCities`,
-`getMunicipalities`, `isValidNcm`, `isValidCbo`, `isValidCnae`, `getBanks`) can be lazy-loaded:
-
-```javascript
-import { isValidCpf } from '@brazilian-utils/brazilian-utils/is-valid-cpf'; // ~1.4 KB, 0.8 KB gzipped
-const { getCities } = await import('@brazilian-utils/brazilian-utils/get-cities'); // only when needed
-```
-
-See [Bundle size](getting-started.md#bundle-size) for the sizes of every entry.
-
-### 📁 Simpler Structure
-
-The codebase has been reorganized for better maintainability:
-- **v1**: Complex structure with separate `utilities/` and `helpers/` directories
-- **v2**: Flat structure with internal utilities in `_internals/` directory
-- Each utility is self-contained in its own directory
-- Cleaner import paths and better code organization
-
-### 🔧 Modern Tooling
-
-Updated to modern, faster tooling:
-- **Build**: Migrated from `tsdx` to a **Vite+** toolchain for faster builds and scripts
-- **Testing**: Migrated from `jest` to **Vitest** (faster, Jest-compatible, ESM-native)
-- **Linting/Formatting**: Migrated from `prettier` + `eslint` to the Vite+ toolchain (`vp fmt` and `vp check`, backed by Oxc)
-- **TypeScript**: Modern configuration optimized for bundlers
-
-### 🌐 Browser Testing
-
-Now includes cross-browser testing support:
-- Tests run in real browsers (Chrome, Firefox, Safari, Edge)
-- Ensures compatibility across different browser environments
-- Better confidence in cross-platform functionality
-
-Run browser tests with:
-```bash
-npm run test:chrome-browser
-npm run test:firefox-browser
-npm run test:safari-browser
-npm run test:edge-browser
-```
-
-### 📦 Fewer Dependencies
-
-Reduced development dependencies while maintaining zero runtime dependencies:
-- **v1**: Multiple tools (tsdx, jest, prettier, eslint, husky, lint-staged, etc.)
-- **v2**: One toolchain (Vite+ for build, lint, format and tests, with Vitest browser support through webdriverio) plus the quality gates listed in CONTRIBUTING.md (Stryker, knip, jscpd, API Extractor, commitlint)
-- Simpler maintenance and faster CI/CD pipelines
-- Zero runtime dependencies (maintained)
-
-### ✨ New Functions & Features
-
-Added new useful utilities:
-- `getHolidays` - Get Brazilian holidays (national and state-specific)
-- `getBoletoInfo` - Extract information from boleto (amount, expiration, bank code)
-- `formatPhone` - Format phone numbers with Brazilian patterns
-- `formatBoleto` - Format boleto numbers
-- `generateBoleto` - Generate valid random boleto numbers
-- `formatPis` - Format PIS numbers
-- `isValidRenavam` - Validate RENAVAM (vehicle registration number)
-- `isValidBankAccount` - Validate Brazilian bank accounts with specific algorithms for major banks
-
-2.4.0 added many more families on top of these, all listed in the [utilities documentation](utilities.md):
-Pix (`isValidPixKey`, `generatePixPayload`, `getPixPayloadInfo`), NF-e/DF-e keys, CNS, certidão,
-CEI/CNO/CAEPF, IBAN, card numbers, VIN, professional registrations, bank lookups (`getBanks`,
-`getBankByCode`, `getBankByIspb`), CBO/CNAE/NCM/CFOP/CST/CSOSN codes, business days
-(`isBusinessDay`, `addBusinessDays`, `differenceInBusinessDays`), legal nature categories, offline
-municipalities (`getMunicipalities`, `getMunicipalityByCode`), DDD and time zone lookups, numbers in
-words, and a `capitalize` that knows the Brazilian company designations.
-
-#### Alphanumeric CNPJ Support (Version 2)
-
-v2.0.0 adds support for the new alphanumeric CNPJ format introduced by the Brazilian Federal Revenue. Both `isValidCnpj` and `generateCnpj` now support version 2 (alphanumeric) CNPJs:
-
-```javascript
-import { isValidCnpj, generateCnpj } from '@brazilian-utils/brazilian-utils';
-
-// Generate alphanumeric CNPJ
-const alphaCnpj = generateCnpj(2); // e.g., "Q0SLFMBD7VX439"
-
-// Validate alphanumeric CNPJ (requires version option)
-isValidCnpj("Q0.SLF.MBD/7VX4-39", { version: 2 }); // true
-isValidCnpj("Q0SLFMBD7VX439", { version: 2 }); // true
-
-// Version 1 (numeric) is the default
-isValidCnpj("12.345.678/0001-95"); // true (validates numeric only)
-isValidCnpj("12.345.678/0001-95", { version: 1 }); // true (explicit)
-```
-
-**Important**: By default, `isValidCnpj()` validates only numeric (version 1) CNPJs. To validate alphanumeric CNPJs, you must explicitly pass `{ version: 2 }`.
-
-### 📈 Better TypeScript Support
-
-- Modern TypeScript configuration optimized for bundlers
-- Better type inference and exports
-- Improved developer experience with better autocomplete
-
-## Breaking Changes
-
-### Function Names Changed (PascalCase → camelCase)
-
-All function names have been changed from PascalCase to camelCase to follow JavaScript naming conventions.
-
-**⚠️ Important: Backward Compatibility**
+| v1 | Replacement |
+|---|---|
+| `onlyNumbers(value)` | `value.replace(/\D/g, '')` |
+| `isLastChar(index, input)` | `index === input.length - 1` |
+| `generateChecksum` | Not exported anymore. Inline the check-digit calculation you need. |
+| `generateRandomNumber(length)` | Your own loop over `Math.floor(Math.random() * 10)`. |
-To make the migration easier, **v2.x still exports the old PascalCase names as deprecated aliases**. This means:
+## What changed
-- ✅ Your existing code using `formatCPF`, `isValidCNPJ`, etc. will continue to work in v2.x
-- ⚠️ You'll receive deprecation warnings in your IDE/TypeScript
-- 🗑️ The old names will be **removed in v3.0.0**
+- **Names are camelCase.** See [Renamed functions](#renamed-functions).
+- **Tree-shaking works down to the function**, and every util is also its own subpath (`@brazilian-utils/brazilian-utils/is-valid-cpf`), so the heavy ones can be lazy-loaded. See [Bundle size](getting-started.md#bundle-size).
+- **Alphanumeric CNPJ.** `isValidCnpj` and `generateCnpj` accept the new alphanumeric format with `{ version: 2 }`. Numeric (version 1) stays the default. See [`generateCnpj` and the version](#generatecnpj-and-the-version).
+- **`getAddressInfoByCep`** accepts a `providers` option, pads a numeric CEP, and throws typed errors: `GetAddressInfoByCepValidationError`, `GetAddressInfoByCepNotFoundError` and `GetAddressInfoByCepServiceError`. Calls without options work as in v1.
+- **`getCities`** returns the list sorted alphabetically. Since 2.4.0 it is deprecated: `getMunicipalities('SP')` returns the same municipalities with their IBGE codes, and `getMunicipalityByCode('3550308')` looks one up offline.
+- **`isValidIe`** takes one object since 2.4.0, `isValidIe({ value, stateCode })`. The positional form is deprecated.
+- **Many new utilities** since v2: holidays and business days, Pix, NF-e keys, boleto parsing, phone formatting, bank accounts and lookups, classification codes (CBO, CNAE, NCM, CFOP), municipalities offline, numbers in words and more. They are all in the [utilities reference](utilities.md).
+- **Tooling** moved to Vite+ and Vitest, with browser tests in CI. This only matters if you contribute; see [CONTRIBUTING.md](https://github.com/brazilian-utils/javascript/blob/main/CONTRIBUTING.md).
-**Recommendation:** While you can upgrade to v2.x without changing your code immediately, we recommend migrating to the new camelCase names as soon as possible to prepare for v3.0.0.
+## Renamed functions
-#### Validation Functions
+Every other export keeps its v1 name.
| v1 | v2 |
|---|---|
@@ -154,63 +40,15 @@ To make the migration easier, **v2.x still exports the old PascalCase names as d
| `isValidCNPJ` | `isValidCnpj` |
| `isValidCEP` | `isValidCep` |
| `isValidPIS` | `isValidPis` |
-| `isValidIE` | `isValidIe` (since 2.4.0 prefer the object form, `isValidIe({ value, stateCode })`; the positional form is deprecated) |
-| `isValidProcessoJuridico` | `isValidProcessoJuridico` (unchanged) |
-| `isValidBoleto` | `isValidBoleto` (unchanged) |
-| `isValidEmail` | `isValidEmail` (unchanged) |
-| `isValidPhone` | `isValidPhone` (unchanged) |
-| `isValidMobilePhone` | `isValidMobilePhone` (unchanged) |
-| `isValidLandlinePhone` | `isValidLandlinePhone` (unchanged) |
-| `isValidLicensePlate` | `isValidLicensePlate` (unchanged) |
-| `isValidRenavam` | `isValidRenavam` (new) |
-
-#### Format Functions
-
-| v1 | v2 |
-|---|---|
+| `isValidIE` | `isValidIe` |
| `formatCPF` | `formatCpf` |
| `formatCNPJ` | `formatCnpj` |
| `formatCEP` | `formatCep` |
-| `formatProcessoJuridico` | `formatProcessoJuridico` (unchanged) |
-| `formatBoleto` | `formatBoleto` (unchanged) |
-| `formatCurrency` | `formatCurrency` (unchanged) |
-| `formatPhone` | `formatPhone` (new) |
-
-#### Generation Functions
-
-| v1 | v2 |
-|---|---|
| `generateCPF` | `generateCpf` |
| `generateCNPJ` | `generateCnpj` |
-| `generateBoleto` | `generateBoleto` (unchanged) |
-
-**⚠️ Note on `generateCnpj` behavior:**
-In v2.x, `generateCnpj()` without arguments defaults to version 1 (numeric CNPJ). In v3.0.0, this behavior will change to randomly select between version 1 (numeric) and version 2 (alphanumeric) CNPJs for better randomness. If you need a specific version, always pass the version parameter explicitly:
+Before (v1):
-```javascript
-// Recommended: Always specify the version
-generateCnpj(1); // Always generates numeric CNPJ
-generateCnpj(2); // Always generates alphanumeric CNPJ
-
-// Not recommended: Relying on default behavior
-generateCnpj(); // Currently generates numeric (v1), but will be random in v3.0.0
-```
-
-#### Other Functions
-
-| v1 | v2 |
-|---|---|
-| `parseCurrency` | `parseCurrency` (unchanged) |
-| `capitalize` | `capitalize` (unchanged) |
-| `getStates` | `getStates` (unchanged) |
-| `getCities` | `getCities` (unchanged; deprecated in 2.4.0 in favour of `getMunicipalities`) |
-| `getMunicipality` | `getMunicipality` (deprecated in 2.4.0 in favour of `getMunicipalityByCode`, which is synchronous and offline) |
-| `getAddressInfoByCep` | `getAddressInfoByCep` (API changed, see below) |
-
-### Migration Example
-
-**Before (v1):**
```javascript
import { isValidCPF, formatCPF, generateCNPJ } from '@brazilian-utils/brazilian-utils';
@@ -219,7 +57,8 @@ const formatted = formatCPF('12345678909');
const cnpj = generateCNPJ();
```
-**After (v2):**
+After (v2):
+
```javascript
import { isValidCpf, formatCpf, generateCnpj } from '@brazilian-utils/brazilian-utils';
@@ -228,176 +67,25 @@ const formatted = formatCpf('12345678909');
const cnpj = generateCnpj();
```
-### Removed Helper Functions
-
-The following helper functions are no longer exported in the public API. These were internal utilities that should not have been exposed.
-
-**⚠️ Note:** Unlike the renamed functions above, these helpers do **NOT** have backward compatibility aliases. You must migrate away from them before upgrading to v2.x.
+### `generateCnpj` and the version
-#### `onlyNumbers`
-This function has been removed from the public API. It's now an internal utility called `sanitizeToDigits`.
+`generateCnpj()` without arguments generates a numeric CNPJ in v2.x. In v3.0.0 it will pick numeric or alphanumeric at random, so pass the version when you need a specific one:
-**Migration:**
```javascript
-// v1 - Don't use this anymore
-import { onlyNumbers } from '@brazilian-utils/brazilian-utils';
-const digits = onlyNumbers('123-456');
-
-// v2 - Use a simple replacement
-const digits = '123-456'.replace(/\D/g, '');
+generateCnpj(1); // always numeric
+generateCnpj(2); // always alphanumeric, e.g. "Q0SLFMBD7VX439"
+generateCnpj(); // numeric today, random in v3.0.0
```
-#### `isLastChar`
-This function has been removed. Use a simple inline comparison instead.
+`isValidCnpj` validates numeric CNPJs by default. To validate alphanumeric ones, pass `{ version: 2 }`:
-**Migration:**
```javascript
-// v1 - Don't use this anymore
-import { isLastChar } from '@brazilian-utils/brazilian-utils';
-if (isLastChar(index, input)) { /* ... */ }
-
-// v2 - Use inline comparison
-if (index === input.length - 1) { /* ... */ }
+isValidCnpj('12.345.678/0001-95'); // true
+isValidCnpj('Q0.SLF.MBD/7VX4-39', { version: 2 }); // true
+isValidCnpj('Q0.SLF.MBD/7VX4-39'); // false (numeric only without the option)
```
-#### `generateChecksum`
-This function is now internal and no longer exported in the public API. The package exports no internals: `dist/_internals` is not published and there is no subpath for it, so there is no supported way to import this function in v2. Inline the check digit calculation you need instead.
-
-**Migration:**
-```javascript
-// v1 - Don't use this anymore
-import { generateChecksum } from '@brazilian-utils/brazilian-utils';
-```
-
-#### `generateRandomNumber`
-This function is now internal and no longer exported in the public API.
-
-**Migration:**
-```javascript
-// v1 - Don't use this anymore
-import { generateRandomNumber } from '@brazilian-utils/brazilian-utils';
-
-// v2 - Use your own implementation
-function generateRandomNumber(length) {
- let result = '';
- for (let i = 0; i < length; i++) {
- result += Math.floor(Math.random() * 10).toString();
- }
- return result;
-}
-```
-
-## New Functions
-
-The following functions are new in v2.0.0:
-
-### `getHolidays`
-
-Get Brazilian holidays for a given year. Supports national and state-specific holidays.
-
-```javascript
-import { getHolidays } from '@brazilian-utils/brazilian-utils';
-
-// Get all national holidays
-const holidays = getHolidays(2024);
-
-// Get holidays for a specific state
-const spHolidays = getHolidays({ year: 2024, stateCode: 'SP' });
-```
-
-### `getBoletoInfo`
-
-Extract information from a boleto (amount, expiration date, bank code).
-
-```javascript
-import { getBoletoInfo } from '@brazilian-utils/brazilian-utils';
-
-const info = getBoletoInfo('00190000090114971860168524522114675860000102656');
-// { amount: 102656, expirationDate: Date, bankCode: '001' }
-```
-
-### `formatPhone`
-
-Format phone numbers according to Brazilian patterns.
-
-```javascript
-import { formatPhone } from '@brazilian-utils/brazilian-utils';
-
-formatPhone('11900000000'); // 11900-0000 (BEWARE: default "sn" truncates a DDD-prefixed number)
-formatPhone('11900000000', { mask: 'nanp' }); // (11) 90000-0000
-formatPhone('11900000000', { mask: 'auto' }); // (11) 90000-0000
-```
-
-### `isValidRenavam`
-
-Validate RENAVAM (Registro Nacional de Veículos Automotores). Supports both old format (9 digits) and new format (11 digits).
-
-```javascript
-import { isValidRenavam } from '@brazilian-utils/brazilian-utils';
-
-isValidRenavam('639884962'); // true (9 digits, old format)
-isValidRenavam('00639884962'); // true (11 digits, new format)
-isValidRenavam('12345678901'); // false (invalid checksum)
-```
-
-### `isValidBankAccount`
-
-Validate Brazilian bank accounts. Supports specific validation algorithms for major banks (Banco do Brasil, Itaú, Bradesco, Santander, Caixa Econômica Federal) and generic mod10/mod11 validation for other banks.
-
-```javascript
-import { isValidBankAccount } from '@brazilian-utils/brazilian-utils';
-
-// Banco do Brasil
-isValidBankAccount({
- bankCode: '001',
- agency: '1584',
- account: '00210169',
- digit: '6'
-}); // true
-
-// Itaú
-isValidBankAccount({
- bankCode: '341',
- agency: '2545',
- account: '02366',
- digit: '1'
-}); // true
-
-// Other banks use generic validation
-isValidBankAccount({
- bankCode: '246',
- agency: '1234',
- account: '123456',
- digit: '6'
-}); // true (the digit matches mod10)
-```
-
-## API Changes
-
-### `getAddressInfoByCep`
-
-The `getAddressInfoByCep` function now supports additional options and improved error handling.
-
-**Before (v1):**
-```javascript
-const address = await getAddressInfoByCep('01310100');
-```
-
-**After (v2):**
-```javascript
-// Still works the same way
-const address = await getAddressInfoByCep('01310100');
-
-// But now supports options
-const address = await getAddressInfoByCep('01310-100', {
- providers: ['viacep', 'brasilapi']
-});
-
-// Also accepts numbers (will be padded automatically)
-const address = await getAddressInfoByCep(1310100);
-```
-
-The function now exports error classes for better error handling:
+### `getAddressInfoByCep` errors
```javascript
import {
@@ -411,58 +99,28 @@ try {
const address = await getAddressInfoByCep('01310100');
} catch (error) {
if (error instanceof GetAddressInfoByCepValidationError) {
- // Handle validation error
+ // invalid CEP
} else if (error instanceof GetAddressInfoByCepNotFoundError) {
- // Handle not found error
+ // no address for this CEP
} else if (error instanceof GetAddressInfoByCepServiceError) {
- // Handle service error
+ // the providers failed
}
}
```
-### `getCities`
-
-The `getCities` function now returns sorted results alphabetically.
-
-**Before (v1):**
-```javascript
-getCities(); // Returned unsorted array
-getCities('SP'); // Returned unsorted array
-```
-
-**After (v2):**
-```javascript
-getCities(); // Returns sorted alphabetically
-getCities('SP'); // Returns sorted alphabetically
-```
-
-**Since 2.4.0:** `getCities` is deprecated. `getMunicipalities('SP')` returns the same municipalities
-with their IBGE codes (`{ code, name, stateCode }`), and `getMunicipalityByCode('3550308')` looks one
-up without a network call.
-
-## Migration Checklist
-
-### Required (before upgrading to v2.x)
-- [ ] Remove usage of helper functions (`onlyNumbers`, `isLastChar`, `generateChecksum`, `generateRandomNumber`)
+## Checklist
-### Optional (recommended before v3.0.0)
-- [ ] Update all imports to use camelCase function names
-- [ ] Replace all function calls with camelCase names
-- [ ] Replace `getCities` with `getMunicipalities` and `getMunicipality` with `getMunicipalityByCode` (deprecated in 2.4.0)
-- [ ] Call `isValidIe({ value, stateCode })` instead of `isValidIe(stateCode, ie)` (deprecated in 2.4.0)
-- [ ] Import the `*Params` type names instead of the `*Options` aliases kept for the single-object-argument functions (deprecated in 2.4.0)
-- [ ] Drop `'widenet'` from the `providers` of `getAddressInfoByCep` (the service is gone; deprecated in 2.4.0)
+Required before upgrading:
-### Review if applicable
-- [ ] Update error handling for `getAddressInfoByCep` if needed
-- [ ] Review usage of `getCities` if sorting was important
-- [ ] Test all validation and formatting functions
-- [ ] Update any TypeScript type imports if applicable
+- [ ] Replace `onlyNumbers`, `isLastChar`, `generateChecksum` and `generateRandomNumber`.
-## Getting Help
+Recommended before v3.0.0:
-If you encounter any issues during migration, please:
+- [ ] Rename the imports and calls in the table above to camelCase.
+- [ ] Replace `getCities` with `getMunicipalities` and `getMunicipality` with `getMunicipalityByCode`.
+- [ ] Call `isValidIe({ value, stateCode })` instead of `isValidIe(stateCode, ie)`.
+- [ ] Import the `*Params` type names instead of the `*Options` aliases of the single-object-argument functions.
+- [ ] Drop `'widenet'` from the `providers` of `getAddressInfoByCep` (the service is gone).
+- [ ] Pass the version to `generateCnpj` when you need a specific one.
-1. Check the [utilities documentation](utilities.md) for the correct function signatures
-2. Review the examples in this migration guide
-3. Open an issue on the [GitHub repository](https://github.com/brazilian-utils/javascript) if you find a bug
+Found a bug during the migration? [Open an issue](https://github.com/brazilian-utils/javascript/issues).
diff --git a/docs/pt-br/_coverpage.md b/docs/pt-br/_coverpage.md
index 68c4d6fa1..c7291e5f3 100644
--- a/docs/pt-br/_coverpage.md
+++ b/docs/pt-br/_coverpage.md
@@ -1,6 +1,6 @@
-> Biblioteca de utilitários para o negócio brasileiro.
+> Utilitários para dados brasileiros: CPF, CNPJ, CEP, boleto, Pix, feriados e mais.
- Zero dependências de runtime
- Tree-shakeable, um import por utilitário
diff --git a/docs/pt-br/_sidebar.md b/docs/pt-br/_sidebar.md
index 58c08e931..38a3dd2a7 100644
--- a/docs/pt-br/_sidebar.md
+++ b/docs/pt-br/_sidebar.md
@@ -1,3 +1,8 @@
* [Introdução](pt-br/getting-started.md)
* [Utilitários](pt-br/utilities.md)
+* Guias
+ * [React](pt-br/guides/react.md)
+ * [Vue](pt-br/guides/vue.md)
+ * [Angular](pt-br/guides/angular.md)
+ * [JavaScript puro](pt-br/guides/vanilla.md)
* [Migração v1 para v2](pt-br/migration-v1-to-v2.md)
diff --git a/docs/pt-br/getting-started.html b/docs/pt-br/getting-started.html
index dc71c6c4c..d4d5cc67c 100644
--- a/docs/pt-br/getting-started.html
+++ b/docs/pt-br/getting-started.html
@@ -4,7 +4,7 @@
Introdução · Brazilian Utils
-
+
@@ -32,7 +32,7 @@
-
+
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/pt-br/getting-started.md b/docs/pt-br/getting-started.md
index 51c7bbb5d..752a7b178 100644
--- a/docs/pt-br/getting-started.md
+++ b/docs/pt-br/getting-started.md
@@ -1,61 +1,44 @@
---
title: "Introdução"
-description: "Instale o Brazilian Utils, a biblioteca de utilitários sem dependências para o business brasileiro, e veja como importar um utilitário, quais runtimes são suportados e como o tamanho do bundle se comporta."
+description: "Instale o Brazilian Utils, a biblioteca sem dependências de utilitários para dados brasileiros, importe um utilitário, veja os runtimes suportados e mantenha o bundle pequeno."
keywords: ["Brazilian Utils", "instalação", "npm", "tree-shaking", "tamanho do bundle", "subpath", "Node.js", "Bun", "Deno", "navegador", "assistentes de IA", "Context7"]
---
-Brazilian Utils é uma biblioteca com foco na resolução de problemas que enfrentamos diariamente no desenvolvimento de aplicações para o business brasileiro.
+Brazilian Utils é uma biblioteca de utilitários, sem dependências, para os problemas do dia a dia de quem desenvolve software para o Brasil: validar, formatar, interpretar e gerar CPF, CNPJ, CEP, boleto, Pix, telefone, feriados e mais.
## Por que Brazilian Utils
-- **Zero dependências de runtime.** Nada além da lib entra no seu `node_modules` ou no seu bundle.
-- **Tree-shakeable até a função.** `import { isValidCpf }` custa cerca de 1,4 KB minificado (0,8 KB com gzip); cada utilitário também é um subpath próprio (`@brazilian-utils/brazilian-utils/get-cities`) para os mais pesados.
-- **Roda em qualquer lugar.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno e navegadores modernos, testados no CI em todos eles.
-- **Escrita em TypeScript.** Os tipos vêm no pacote; a API pública é acompanhada por um relatório de API, então nada muda em silêncio.
-- **Validada contra as regras oficiais.** Cada validador cita a especificação, lei ou base de dados que implementa (`@see` na documentação), e a suíte de testes passa por mutation testing, não só por cobertura.
+- **Zero dependências de runtime.** Nada além da biblioteca entra no seu `node_modules` ou no seu bundle.
+- **Tree-shakeable até a função.** `import { isValidCpf }` custa cerca de 1,4 KB minificado (0,8 KB com gzip). Cada utilitário também é um subpath próprio, então os pesados podem ser carregados sob demanda.
+- **Roda em qualquer lugar.** Node.js `^20.19.0 || >=22.12.0`, Bun, Deno e navegadores modernos, todos testados no CI.
+- **Escrita em TypeScript.** Os tipos vêm no pacote, e um relatório de API acompanha a API pública para que nada mude em silêncio.
+- **Validada contra as regras oficiais.** Cada validador cita a especificação, lei ou base de dados que implementa, e a suíte de testes passa por mutation testing, não só por cobertura.
- **Documentada em inglês e português**, com um `llms.txt` para assistentes de IA.
## Instalação
-Você pode instalar o **Brazilian Utils** de algumas formas:
-
-como um pacote npm:
-
-```bash
-npm install --save @brazilian-utils/brazilian-utils
-```
-
-com gerenciador de pacotes yarn:
-
```bash
-yarn add @brazilian-utils/brazilian-utils
+npm install @brazilian-utils/brazilian-utils
```
-com pnpm:
-
-```bash
-pnpm add @brazilian-utils/brazilian-utils
-```
-
-com bun:
-
-```bash
-bun add @brazilian-utils/brazilian-utils
-```
-
-ou `
```
-### Suporte a runtimes
+### Runtimes suportados
-Node `^20.19.0 || >=22.12.0`, Bun, Deno e navegadores modernos.
+| Runtime | Suportado | Testado no CI |
+| ----------- | ------------------------- | ----------------------------- |
+| Node.js | `^20.19.0 \|\| >=22.12.0` | 20, 22, 24, 26 |
+| Bun | mais recente | mais recente |
+| Deno | 2.x | 2.x |
+| Navegadores | modernos | Chrome, Firefox, Edge, Safari |
## Como usar
-Para usar um de nossos utilitários, basta importar a função necessária, como no exemplo abaixo:
+Importe a função que precisar:
```javascript
import { isValidCpf } from '@brazilian-utils/brazilian-utils';
@@ -63,7 +46,7 @@ import { isValidCpf } from '@brazilian-utils/brazilian-utils';
isValidCpf('1232454233345'); // false
```
-Você pode conferir a lista de utilitários [clicando aqui](pt-br/utilities.md).
+A [referência de utilitários](pt-br/utilities.md) lista todas as funções, agrupadas por família, com opções e exemplos.
## Assistentes de IA
@@ -73,17 +56,17 @@ A documentação está indexada no Context7 como [`/brazilian-utils/javascript`]
Valide um CNPJ com o Brazilian Utils. use library /brazilian-utils/javascript
```
-Para não repetir isso a cada prompt, coloque a regra no arquivo de instruções do agente (`CLAUDE.md`, regras do Cursor ou equivalente): "Para utilitários de documentos brasileiros, use a biblioteca /brazilian-utils/javascript do Context7".
+Para não repetir isso a cada prompt, coloque uma regra no arquivo de instruções do agente (`CLAUDE.md`, regras do Cursor ou equivalente): "Para utilitários de documentos brasileiros, use a biblioteca /brazilian-utils/javascript do Context7".
-Sem o Context7, aponte o assistente para o [llms.txt](https://brazilian-utils.com.br/llms.txt), que lista todos os utilitários com uma descrição de uma linha e o link para a seção de cada um, ou para o [llms-full.txt](https://brazilian-utils.com.br/llms-full.txt), a documentação completa em inglês em um único arquivo Markdown.
+Sem o Context7, aponte o assistente para o [llms.txt](https://brazilian-utils.com.br/llms.txt), que lista todos os utilitários com uma descrição de uma linha, ou para o [llms-full.txt](https://brazilian-utils.com.br/llms-full.txt), a documentação completa em inglês em um único arquivo Markdown.
## Tamanho do bundle
-O pacote é tree-shakeable: importar um utilitário da raiz traz apenas o código daquele utilitário, não o resto da biblioteca. `isValidCpf`, por exemplo, adiciona cerca de 1,4 KB minificado (0,8 KB com gzip) ao seu bundle. Um bundler com suporte a tree-shaking (webpack, Rollup, esbuild, Vite, etc.) descarta todos os outros utilitários.
+O pacote é tree-shakeable: importar um utilitário da raiz traz apenas o código daquele utilitário. `isValidCpf`, por exemplo, adiciona cerca de 1,4 KB minificado (0,8 KB com gzip) ao seu bundle.
-Alguns utilitários são a exceção: cada um embute um dataset oficial e pesa muito mais que todos os outros utilitários somados. Estes são os tamanhos de um import isolado, minificado e com gzip:
+Alguns utilitários embutem uma base de dados oficial e pesam muito mais que todos os outros somados:
-| Utilitário | Dataset | Minificado | Gzip |
+| Utilitário | Base de dados | Minificado | Gzip |
| --- | --- | --- | --- |
| `getMunicipalities` · `getMunicipalityByCode` · `getMunicipality` | 5571 municípios do IBGE, com nomes e códigos | 154,9 - 156,5 KB | 50,3 - 50,4 KB |
| `getCities` | nomes dos 5571 municípios do IBGE | 154,2 KB | 49,8 KB |
@@ -93,9 +76,7 @@ Alguns utilitários são a exceção: cada um embute um dataset oficial e pesa m
| `isValidCfop` · `getCfop` | descrições das operações do CFOP | 68,9 KB | 6,9 KB |
| `getBanks` · `getBankByCode` · `getBankByIspb` | participantes do STR do Banco Central (COMPE + ISPB) | 38,3 - 38,6 KB | 9,5 - 9,7 KB |
-Importar qualquer um deles da raiz, mesmo ao lado de um único utilitário pequeno, traz todo esse dataset para o seu bundle principal, porque este pacote é publicado como um único módulo ESM: um `import()` dinâmico da raiz (`await import('@brazilian-utils/brazilian-utils')`) ainda resolve para esse mesmo arquivo único, então não há como separá-lo sozinho. Um bundler que faz code-splitting precisa de um módulo separado para separar.
-
-Esses módulos separados são os subpaths por utilitário. Carregue um utilitário pesado sob demanda, apenas onde você realmente precisar dos dados dele:
+A raiz do pacote é um único módulo ESM, então o bundler não consegue separar uma dessas bases de dados dele: importar um utilitário pesado da raiz coloca a base inteira no seu bundle principal, e um `import()` dinâmico da raiz não ajuda. Para carregar sob demanda, importe do subpath próprio:
```javascript
const { getCities } = await import('@brazilian-utils/brazilian-utils/get-cities');
@@ -111,6 +92,6 @@ const { getMunicipalityByCode } = await import(
getMunicipalityByCode('3550308');
```
-Todos os utilitários estão disponíveis dessa forma, como `@brazilian-utils/brazilian-utils/` (kebab-case, seguindo o nome da função: `isValidCpf` → `is-valid-cpf`), pelo mesmo motivo de lazy-loading/code-splitting.
+Todo utilitário tem um subpath, `@brazilian-utils/brazilian-utils/` em kebab-case (`isValidCpf` vira `is-valid-cpf`).
-Escolha um estilo por utilitário em cada aplicação: um bundler trata o import da raiz e o import do subpath como dois módulos independentes, então importar `getCities` tanto da raiz quanto de `/get-cities` na mesma aplicação inclui a tabela de 154,2 KB de cidades duas vezes, uma em cada módulo.
+Escolha um estilo por utilitário em cada aplicação. O bundler trata o import da raiz e o import do subpath como dois módulos independentes, então importar `getCities` dos dois inclui a tabela de municípios duas vezes.
diff --git a/docs/pt-br/guides/angular.html b/docs/pt-br/guides/angular.html
new file mode 100644
index 000000000..210e84c3b
--- /dev/null
+++ b/docs/pt-br/guides/angular.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Uso com Angular · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/pt-br/guides/angular.md b/docs/pt-br/guides/angular.md
new file mode 100644
index 000000000..49d0cc792
--- /dev/null
+++ b/docs/pt-br/guides/angular.md
@@ -0,0 +1,382 @@
+---
+title: "Uso com Angular"
+description: "Valide e formate documentos brasileiros em formulários Angular: signals, máscaras de input, formulários reativos com validadores próprios e esquemas de formulário com zod ou valibot, com exemplos executáveis."
+keywords: ["Angular", "signals", "formulários reativos", "validadores", "máscara de input", "zod", "valibot", "CPF", "CNPJ", "CEP", "telefone"]
+---
+
+O Brazilian Utils não tem código Angular: cada função recebe um valor e retorna um valor, então funciona em um signal, em um validador ou em um pipe. Esta página mostra os padrões que aparecem na maioria das aplicações, como componentes standalone com signals (Angular 22, sem zone.js). Todos os exemplos rodam no navegador: clique em **Executar** embaixo do código.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validar enquanto o usuário digita
+
+Guarde o input em um signal e derive a validade com `computed`. O validador aceita o valor com ou sem máscara, então não é preciso limpar nada antes.
+
+```typescript
+import { Component, computed, signal } from '@angular/core';
+import { isValidCpf } from '@brazilian-utils/brazilian-utils';
+
+@Component({
+ selector: 'app-root',
+ template: `
+
+ CPF
+
+ @if (cpf()) {
+ {{ valid() ? 'CPF válido' : 'CPF inválido' }}
+ }
+
+ `,
+})
+export default class CpfField {
+ cpf = signal('');
+ valid = computed(() => isValidCpf(this.cpf()));
+}
+```
+
+## Formatar enquanto digita (máscara de input)
+
+As funções `format*` aplicam a máscara até onde o valor vai, então gravar o valor formatado no signal a cada evento `input` já é uma máscara de input, sem biblioteca extra. Use `{ mask: 'nanp' }` para telefone com DDD.
+
+```typescript
+import { Component, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { formatCep, formatCnpj, formatCpf, formatPhone } from '@brazilian-utils/brazilian-utils';
+
+const masks = {
+ cpf: formatCpf,
+ cnpj: formatCnpj,
+ phone: (value: string) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+type Field = keyof typeof masks;
+
+@Component({
+ selector: 'app-root',
+ imports: [JsonPipe],
+ template: `
+
+ `,
+})
+export default class MaskedInputs {
+ fields: { name: Field; label: string; placeholder: string }[] = [
+ { name: 'cpf', label: 'CPF', placeholder: '000.000.000-00' },
+ { name: 'cnpj', label: 'CNPJ', placeholder: '00.000.000/0000-00' },
+ { name: 'phone', label: 'Telefone', placeholder: '(00) 00000-0000' },
+ { name: 'cep', label: 'CEP', placeholder: '00000-000' },
+ ];
+
+ values = signal>({ cpf: '', cnpj: '', phone: '', cep: '' });
+
+ update(name: Field, event: Event) {
+ const value = masks[name]((event.target as HTMLInputElement).value);
+ this.values.update((current) => ({ ...current, [name]: value }));
+ }
+}
+```
+
+## Validar um formulário reativo
+
+Um validador é uma função que recebe o controle e retorna um objeto de erro, então qualquer `isValid*` vira um em uma linha. As máscaras ficam no evento `input`, e `parse*` tira a máscara antes de os dados saírem do formulário.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { AbstractControl, NonNullableFormBuilder, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const validator = (check: (value: string) => boolean) =>
+ (control: AbstractControl): ValidationErrors | null => (check(control.value) ? null : { invalid: true });
+
+const masks: Partial string>> = {
+ cpf: formatCpf,
+ phone: (value) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+const messages = { name: 'Informe o nome', cpf: 'CPF inválido', phone: 'Telefone inválido', cep: 'CEP inválido' };
+
+type Field = keyof typeof messages;
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class SignupForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['name', 'cpf', 'phone', 'cep'];
+
+ form = this.fb.group({
+ name: ['', [Validators.required, Validators.minLength(2)]],
+ cpf: ['', validator(isValidCpf)],
+ phone: ['', validator((value) => isValidPhone(value))],
+ cep: ['', validator(isValidCep)],
+ });
+
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ const format = masks[name];
+ if (format) this.form.controls[name].setValue(format((event.target as HTMLInputElement).value));
+ }
+
+ error(name: Field) {
+ const control = this.form.controls[name];
+ return control.touched && control.invalid ? messages[name] : '';
+ }
+
+ submit() {
+ this.form.markAllAsTouched();
+ if (this.form.invalid) {
+ this.data.set(null);
+ return;
+ }
+ const { name, cpf, phone, cep } = this.form.getRawValue();
+ this.data.set({ name, cpf: parseCpf(cpf), phone: parsePhone(phone), cep: parseCep(cep) });
+ }
+}
+```
+
+## Validar um formulário com zod
+
+Coloque o validador em um `refine` e o parser em um `transform`: o esquema rejeita um documento inválido com a sua mensagem e entrega os dígitos de um válido, prontos para a API. O formulário fica simples; o zod roda no envio.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';
+import { z } from 'zod';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = z.object({
+ name: z.string().min(2, 'Informe o nome'),
+ cpf: z.string().refine(isValidCpf, 'CPF inválido').transform(parseCpf),
+ phone: z.string().refine((value) => isValidPhone(value), 'Telefone inválido').transform(parsePhone),
+ cep: z.string().refine(isValidCep, 'CEP inválido').transform(parseCep),
+});
+
+type Field = keyof z.infer;
+
+const masks: Partial string>> = {
+ cpf: formatCpf,
+ phone: (value) => formatPhone(value, { mask: 'nanp' }),
+ cep: formatCep,
+};
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class SignupForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['name', 'cpf', 'phone', 'cep'];
+ form = this.fb.group({ name: '', cpf: '', phone: '', cep: '' });
+ errors = signal>>({});
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ const format = masks[name];
+ if (format) this.form.controls[name].setValue(format((event.target as HTMLInputElement).value));
+ }
+
+ submit() {
+ const result = schema.safeParse(this.form.getRawValue());
+ if (!result.success) {
+ this.errors.set(Object.fromEntries(result.error.issues.map((issue) => [issue.path[0], issue.message])));
+ this.data.set(null);
+ return;
+ }
+ this.errors.set({});
+ this.data.set(result.data);
+ }
+}
+```
+
+## Validar um formulário com valibot
+
+A mesma ideia no valibot: `check` para o validador, `transform` para o parser, `flatten` para ler as mensagens por campo.
+
+```typescript
+import { Component, inject, signal } from '@angular/core';
+import { JsonPipe } from '@angular/common';
+import { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';
+import * as v from 'valibot';
+import {
+ formatCnpj, formatCpf,
+ isValidCnpj, isValidCpf,
+ parseCnpj, parseCpf,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = v.object({
+ cpf: v.pipe(v.string(), v.check(isValidCpf, 'CPF inválido'), v.transform(parseCpf)),
+ cnpj: v.pipe(v.string(), v.check((value) => isValidCnpj(value), 'CNPJ inválido'), v.transform(parseCnpj)),
+});
+
+type Field = keyof v.InferInput;
+
+const masks: Record string> = { cpf: formatCpf, cnpj: formatCnpj };
+
+@Component({
+ selector: 'app-root',
+ imports: [ReactiveFormsModule, JsonPipe],
+ template: `
+
+ `,
+})
+export default class CompanyForm {
+ private fb = inject(NonNullableFormBuilder);
+
+ names: Field[] = ['cpf', 'cnpj'];
+ form = this.fb.group({ cpf: '', cnpj: '' });
+ errors = signal>>({});
+ data = signal(null);
+
+ mask(name: Field, event: Event) {
+ this.form.controls[name].setValue(masks[name]((event.target as HTMLInputElement).value));
+ }
+
+ submit() {
+ const result = v.safeParse(schema, this.form.getRawValue());
+ if (!result.success) {
+ const nested = v.flatten(result.issues).nested ?? {};
+ this.errors.set(Object.fromEntries(Object.entries(nested).map(([field, messages]) => [field, messages?.[0]])));
+ this.data.set(null);
+ return;
+ }
+ this.errors.set({});
+ this.data.set(result.output);
+ }
+}
+```
+
+## Formatar para exibição
+
+Guarde os dígitos, formate no template. Exponha as funções que precisar como campos do componente (ou embrulhe uma delas em um pipe). `formatCpf` pode esconder os dígitos como o gov.br faz, e `formatPhone` com `mask: 'auto'` escolhe o padrão certo a partir do próprio número.
+
+```typescript
+import { Component } from '@angular/core';
+import {
+ convertCurrencyToWords, formatCnpj, formatCpf, formatCurrency, formatPhone,
+} from '@brazilian-utils/brazilian-utils';
+
+@Component({
+ selector: 'app-root',
+ template: `
+
+ Cliente
+ {{ order.customer }} ({{ formatCpf(order.cpf, { obfuscate: true }) }})
+ Empresa
+ {{ order.company }}, CNPJ {{ formatCnpj(order.cnpj) }}
+ Telefone
+ {{ formatPhone(order.phone, { mask: 'auto' }) }}
+ Total
+
+ {{ formatCurrency(order.total, { symbol: true }) }}
+
+ {{ convertCurrencyToWords(order.total) }}
+
+
+ `,
+})
+export default class Receipt {
+ order = {
+ customer: 'Maria da Silva',
+ cpf: '12345678909',
+ company: 'ACME LTDA',
+ cnpj: '12345678000195',
+ phone: '11987654321',
+ total: 1234.56,
+ };
+
+ protected readonly formatCpf = formatCpf;
+ protected readonly formatCnpj = formatCnpj;
+ protected readonly formatPhone = formatPhone;
+ protected readonly formatCurrency = formatCurrency;
+ protected readonly convertCurrencyToWords = convertCurrencyToWords;
+}
+```
+
+## Para onde ir depois
+
+- A [referência de utilitários](pt-br/utilities.md) lista todas as funções com suas opções.
+- Os mesmos padrões em [React](pt-br/guides/react.md), [Vue](pt-br/guides/vue.md) e [JavaScript puro](pt-br/guides/vanilla.md).
+- Utilitários pesados como `getMunicipalities` merecem um import sob demanda; veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle).
diff --git a/docs/pt-br/guides/react.html b/docs/pt-br/guides/react.html
new file mode 100644
index 000000000..266707a60
--- /dev/null
+++ b/docs/pt-br/guides/react.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Uso com React · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/pt-br/guides/react.md b/docs/pt-br/guides/react.md
new file mode 100644
index 000000000..6dc353bdd
--- /dev/null
+++ b/docs/pt-br/guides/react.md
@@ -0,0 +1,245 @@
+---
+title: "Uso com React"
+description: "Valide e formate documentos brasileiros em formulários React: máscaras de input, validação enquanto o usuário digita e esquemas de formulário com zod ou valibot, com exemplos executáveis."
+keywords: ["React", "formulário", "máscara de input", "zod", "valibot", "react-hook-form", "CPF", "CNPJ", "CEP", "telefone"]
+---
+
+O Brazilian Utils não tem código React: cada função recebe um valor e retorna um valor, então se encaixa em qualquer componente, hook ou biblioteca de formulário. Esta página mostra os padrões que aparecem na maioria das aplicações. Todos os exemplos rodam no navegador: clique em **Executar** embaixo do código.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validar enquanto o usuário digita
+
+Guarde o input no estado e consulte o validador a cada render. O validador aceita o valor com ou sem máscara, então não é preciso limpar nada antes.
+
+```jsx
+import { useState } from 'react';
+import { isValidCpf } from '@brazilian-utils/brazilian-utils';
+
+export default function CpfField() {
+ const [cpf, setCpf] = useState('');
+ const valid = isValidCpf(cpf);
+
+ return (
+
+ CPF
+ setCpf(event.target.value)}
+ placeholder="000.000.000-00"
+ inputMode="numeric"
+ />
+ {cpf && {valid ? 'CPF válido' : 'CPF inválido'} }
+
+ );
+}
+```
+
+## Formatar enquanto digita (máscara de input)
+
+As funções `format*` aplicam a máscara até onde o valor vai, então passar o que foi digitado por uma delas a cada mudança já é uma máscara de input, sem biblioteca extra. Use `{ mask: 'nanp' }` para telefone com DDD.
+
+```jsx
+import { useState } from 'react';
+import { formatCep, formatCnpj, formatCpf, formatPhone } from '@brazilian-utils/brazilian-utils';
+
+const fields = [
+ { name: 'cpf', label: 'CPF', format: formatCpf, placeholder: '000.000.000-00' },
+ { name: 'cnpj', label: 'CNPJ', format: formatCnpj, placeholder: '00.000.000/0000-00' },
+ { name: 'phone', label: 'Telefone', format: (value) => formatPhone(value, { mask: 'nanp' }), placeholder: '(00) 00000-0000' },
+ { name: 'cep', label: 'CEP', format: formatCep, placeholder: '00000-000' },
+];
+
+export default function MaskedInputs() {
+ const [values, setValues] = useState({ cpf: '', cnpj: '', phone: '', cep: '' });
+
+ return (
+
+ );
+}
+```
+
+## Validar um formulário com zod
+
+Coloque o validador em um `refine` e o parser em um `transform`: o esquema rejeita um documento inválido com a sua mensagem e entrega os dígitos de um válido, prontos para a API.
+
+```jsx
+import { useState } from 'react';
+import { z } from 'zod';
+import {
+ formatCep, formatCpf, formatPhone,
+ isValidCep, isValidCpf, isValidPhone,
+ parseCep, parseCpf, parsePhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = z.object({
+ name: z.string().min(2, 'Informe o nome'),
+ cpf: z.string().refine(isValidCpf, 'CPF inválido').transform(parseCpf),
+ phone: z.string().refine((value) => isValidPhone(value), 'Telefone inválido').transform(parsePhone),
+ cep: z.string().refine(isValidCep, 'CEP inválido').transform(parseCep),
+});
+
+const masks = { cpf: formatCpf, phone: (value) => formatPhone(value, { mask: 'nanp' }), cep: formatCep };
+
+export default function SignupForm() {
+ const [values, setValues] = useState({ name: '', cpf: '', phone: '', cep: '' });
+ const [errors, setErrors] = useState({});
+ const [data, setData] = useState(null);
+
+ function change(event) {
+ const { name, value } = event.target;
+ setValues({ ...values, [name]: masks[name] ? masks[name](value) : value });
+ }
+
+ function submit(event) {
+ event.preventDefault();
+ const result = schema.safeParse(values);
+ if (!result.success) {
+ setErrors(Object.fromEntries(result.error.issues.map((issue) => [issue.path[0], issue.message])));
+ setData(null);
+ return;
+ }
+ setErrors({});
+ setData(result.data);
+ }
+
+ return (
+
+ );
+}
+```
+
+Com react-hook-form, o mesmo esquema vai no resolver e os campos são registrados como de costume:
+
+```jsx
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+
+const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(schema) });
+```
+
+## Validar um formulário com valibot
+
+A mesma ideia no valibot: `check` para o validador, `transform` para o parser, `flatten` para ler as mensagens por campo.
+
+```jsx
+import { useState } from 'react';
+import * as v from 'valibot';
+import {
+ formatCnpj, formatCpf,
+ isValidCnpj, isValidCpf,
+ parseCnpj, parseCpf,
+} from '@brazilian-utils/brazilian-utils';
+
+const schema = v.object({
+ cpf: v.pipe(v.string(), v.check(isValidCpf, 'CPF inválido'), v.transform(parseCpf)),
+ cnpj: v.pipe(v.string(), v.check((value) => isValidCnpj(value), 'CNPJ inválido'), v.transform(parseCnpj)),
+});
+
+const masks = { cpf: formatCpf, cnpj: formatCnpj };
+
+export default function CompanyForm() {
+ const [values, setValues] = useState({ cpf: '', cnpj: '' });
+ const [errors, setErrors] = useState({});
+ const [data, setData] = useState(null);
+
+ function submit(event) {
+ event.preventDefault();
+ const result = v.safeParse(schema, values);
+ if (!result.success) {
+ const nested = v.flatten(result.issues).nested ?? {};
+ setErrors(Object.fromEntries(Object.entries(nested).map(([field, messages]) => [field, messages[0]])));
+ setData(null);
+ return;
+ }
+ setErrors({});
+ setData(result.output);
+ }
+
+ return (
+
+ );
+}
+```
+
+## Formatar para exibição
+
+Guarde os dígitos, formate na hora de renderizar. `formatCpf` pode esconder os dígitos como o gov.br faz, e `formatPhone` com `mask: 'auto'` escolhe o padrão certo a partir do próprio número.
+
+```jsx
+import {
+ convertCurrencyToWords, formatCnpj, formatCpf, formatCurrency, formatPhone,
+} from '@brazilian-utils/brazilian-utils';
+
+const order = {
+ customer: 'Maria da Silva',
+ cpf: '12345678909',
+ company: 'ACME LTDA',
+ cnpj: '12345678000195',
+ phone: '11987654321',
+ total: 1234.56,
+};
+
+export default function Receipt() {
+ return (
+
+ Cliente
+ {order.customer} ({formatCpf(order.cpf, { obfuscate: true })})
+ Empresa
+ {order.company}, CNPJ {formatCnpj(order.cnpj)}
+ Telefone
+ {formatPhone(order.phone, { mask: 'auto' })}
+ Total
+
+ {formatCurrency(order.total, { symbol: true })}
+
+ {convertCurrencyToWords(order.total)}
+
+
+ );
+}
+```
+
+## Para onde ir depois
+
+- A [referência de utilitários](pt-br/utilities.md) lista todas as funções com suas opções.
+- Os mesmos padrões em [Vue](pt-br/guides/vue.md), [Angular](pt-br/guides/angular.md) e [JavaScript puro](pt-br/guides/vanilla.md).
+- Utilitários pesados como `getMunicipalities` merecem um import sob demanda; veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle).
diff --git a/docs/pt-br/guides/vanilla.html b/docs/pt-br/guides/vanilla.html
new file mode 100644
index 000000000..b7c5c9e99
--- /dev/null
+++ b/docs/pt-br/guides/vanilla.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Uso com JavaScript puro · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/pt-br/guides/vanilla.md b/docs/pt-br/guides/vanilla.md
new file mode 100644
index 000000000..df5afe662
--- /dev/null
+++ b/docs/pt-br/guides/vanilla.md
@@ -0,0 +1,261 @@
+---
+title: "Uso com JavaScript puro"
+description: "Valide e formate documentos brasileiros sem framework: máscaras de input em um formulário comum, validação no envio e esquemas de formulário com zod ou valibot, com exemplos executáveis."
+keywords: ["vanilla", "JavaScript", "formulário", "máscara de input", "zod", "valibot", "tag script", "UMD", "CPF", "CNPJ", "CEP", "telefone"]
+---
+
+Não precisa de framework: cada função recebe um valor e retorna um valor. Os exemplos desta página são arquivos HTML completos que carregam o pacote de um CDN por um import map, então rodam como estão, no navegador ou em um arquivo no seu disco. Clique em **Executar** embaixo do código. Com um bundler, tire o import map e faça `npm install @brazilian-utils/brazilian-utils`.
+
+## Carregar o pacote
+
+Como módulo ES, com um import map (o que os exemplos abaixo fazem):
+
+```html
+
+
+```
+
+Ou como script clássico, que expõe a global `BrazilianUtils`:
+
+```html
+
+
+```
+
+## Validar enquanto o usuário digita
+
+Escute o evento `input` e consulte o validador. Ele aceita o valor com ou sem máscara, então não é preciso limpar nada antes.
+
+```html
+
+
+
+
+ CPF
+
+
+
+
+
+
+
+
+```
+
+## Formatar enquanto digita (máscara de input)
+
+As funções `format*` aplicam a máscara até onde o valor vai, então escrever o valor formatado de volta a cada evento `input` já é uma máscara de input, sem biblioteca extra. Use `{ mask: 'nanp' }` para telefone com DDD.
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+## Validar um formulário com zod
+
+Coloque o validador em um `refine` e o parser em um `transform`: o esquema rejeita um documento inválido com a sua mensagem e entrega os dígitos de um válido, prontos para a API.
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## Validar um formulário com valibot
+
+A mesma ideia no valibot: `check` para o validador, `transform` para o parser, `flatten` para ler as mensagens por campo.
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## Formatar para exibição
+
+Guarde os dígitos, formate na hora de renderizar. `formatCpf` pode esconder os dígitos como o gov.br faz, e `formatPhone` com `mask: 'auto'` escolhe o padrão certo a partir do próprio número.
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+## Para onde ir depois
+
+- A [referência de utilitários](pt-br/utilities.md) lista todas as funções com suas opções.
+- Os mesmos padrões em [React](pt-br/guides/react.md), [Vue](pt-br/guides/vue.md) e [Angular](pt-br/guides/angular.md).
+- Utilitários pesados como `getMunicipalities` merecem um import sob demanda; veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle).
diff --git a/docs/pt-br/guides/vue.html b/docs/pt-br/guides/vue.html
new file mode 100644
index 000000000..b3b777928
--- /dev/null
+++ b/docs/pt-br/guides/vue.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+ Uso com Vue · Brazilian Utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This site renders its Markdown in the browser and needs JavaScript. The same pages are available as
+ plain Markdown: getting started , utilities ,
+ migration from v1 to v2 and the
+ Portuguese version , or in one file at llms-full.txt .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/pt-br/guides/vue.md b/docs/pt-br/guides/vue.md
new file mode 100644
index 000000000..dafa2b242
--- /dev/null
+++ b/docs/pt-br/guides/vue.md
@@ -0,0 +1,226 @@
+---
+title: "Uso com Vue"
+description: "Valide e formate documentos brasileiros em formulários Vue: máscaras de input com v-model, validação enquanto o usuário digita e esquemas de formulário com zod ou valibot, com exemplos executáveis."
+keywords: ["Vue", "formulário", "v-model", "máscara de input", "zod", "valibot", "vee-validate", "CPF", "CNPJ", "CEP", "telefone"]
+---
+
+O Brazilian Utils não tem código Vue: cada função recebe um valor e retorna um valor, então se encaixa em um `ref`, um `computed` ou qualquer biblioteca de formulário. Esta página mostra os padrões que aparecem na maioria das aplicações, como componentes de arquivo único. Todos os exemplos rodam no navegador: clique em **Executar** embaixo do código.
+
+```bash
+npm install @brazilian-utils/brazilian-utils
+```
+
+## Validar enquanto o usuário digita
+
+Guarde o input em um `ref` e derive a validade com `computed`. O validador aceita o valor com ou sem máscara, então não é preciso limpar nada antes.
+
+```vue
+
+
+
+
+ CPF
+
+ {{ valid ? 'CPF válido' : 'CPF inválido' }}
+
+
+```
+
+## Formatar enquanto digita (máscara de input)
+
+Um `computed` com setter transforma qualquer função `format*` em uma máscara de `v-model`: o setter formata o que foi digitado, o getter retorna o valor. Use `{ mask: 'nanp' }` para telefone com DDD.
+
+```vue
+
+
+
+
+
+```
+
+## Validar um formulário com zod
+
+Coloque o validador em um `refine` e o parser em um `transform`: o esquema rejeita um documento inválido com a sua mensagem e entrega os dígitos de um válido, prontos para a API.
+
+```vue
+
+
+
+
+
+```
+
+Com vee-validate, o mesmo esquema passa por `toTypedSchema` e os campos são ligados com `useField` ou ``:
+
+```javascript
+import { useForm } from 'vee-validate';
+import { toTypedSchema } from '@vee-validate/zod';
+
+const { handleSubmit, errors } = useForm({ validationSchema: toTypedSchema(schema) });
+```
+
+## Validar um formulário com valibot
+
+A mesma ideia no valibot: `check` para o validador, `transform` para o parser, `flatten` para ler as mensagens por campo.
+
+```vue
+
+
+
+
+
+```
+
+## Formatar para exibição
+
+Guarde os dígitos, formate no template. `formatCpf` pode esconder os dígitos como o gov.br faz, e `formatPhone` com `mask: 'auto'` escolhe o padrão certo a partir do próprio número.
+
+```vue
+
+
+
+
+ Cliente
+ {{ order.customer }} ({{ formatCpf(order.cpf, { obfuscate: true }) }})
+ Empresa
+ {{ order.company }}, CNPJ {{ formatCnpj(order.cnpj) }}
+ Telefone
+ {{ formatPhone(order.phone, { mask: 'auto' }) }}
+ Total
+
+ {{ formatCurrency(order.total, { symbol: true }) }}
+
+ {{ convertCurrencyToWords(order.total) }}
+
+
+
+```
+
+## Para onde ir depois
+
+- A [referência de utilitários](pt-br/utilities.md) lista todas as funções com suas opções.
+- Os mesmos padrões em [React](pt-br/guides/react.md), [Angular](pt-br/guides/angular.md) e [JavaScript puro](pt-br/guides/vanilla.md).
+- Utilitários pesados como `getMunicipalities` merecem um import sob demanda; veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle).
diff --git a/docs/pt-br/index.html b/docs/pt-br/index.html
index dc71c6c4c..d4d5cc67c 100644
--- a/docs/pt-br/index.html
+++ b/docs/pt-br/index.html
@@ -4,7 +4,7 @@
Introdução · Brazilian Utils
-
+
@@ -32,7 +32,7 @@
-
+
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/pt-br/migration-v1-to-v2.html b/docs/pt-br/migration-v1-to-v2.html
index 4871841de..013287e1f 100644
--- a/docs/pt-br/migration-v1-to-v2.html
+++ b/docs/pt-br/migration-v1-to-v2.html
@@ -3,8 +3,8 @@
- Guia de Migração: v1 para v2 · Brazilian Utils
-
+ Guia de migração: v1 para v2 · Brazilian Utils
+
@@ -31,8 +31,8 @@
-
-
+
+
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/pt-br/migration-v1-to-v2.md b/docs/pt-br/migration-v1-to-v2.md
index 21edcf90d..28c89f703 100644
--- a/docs/pt-br/migration-v1-to-v2.md
+++ b/docs/pt-br/migration-v1-to-v2.md
@@ -1,153 +1,38 @@
---
-title: "Guia de Migração: v1 para v2"
-description: "Como migrar um projeto do Brazilian Utils v1.x para a v2: os exports renomeados, os aliases deprecados que ainda funcionam e um checklist para seguir."
-keywords: ["migração", "v1", "v2", "deprecado", "exports renomeados", "atualização"]
+title: "Guia de migração: v1 para v2"
+description: "Como migrar um projeto do Brazilian Utils v1.x para a v2: os exports renomeados, os aliases descontinuados que ainda funcionam e um checklist para seguir."
+keywords: ["migração", "v1", "v2", "descontinuado", "exports renomeados", "atualização"]
---
-Este guia irá ajudá-lo a migrar do Brazilian Utils v1.x para v2.0.0.
+Este guia mostra como migrar um projeto do Brazilian Utils v1.x para a v2.
-## TL;DR - Migração Rápida
+## Resumo
-**Boas notícias!** A v2.x mantém compatibilidade para a maioria das mudanças quebradoras:
+A v2 renomeia todas as funções para camelCase (`formatCPF` agora é `formatCpf`), mas mantém os nomes da v1 como aliases descontinuados, então a maioria dos projetos atualiza sem mudar código. O TypeScript e o editor marcam os nomes antigos. Os aliases são removidos na v3.0.0.
-**Você pode atualizar para v2.x sem alterar seu código** - nomes antigos de funções como `formatCPF`, `isValidCNPJ`, etc. ainda funcionam
-**Você receberá avisos de deprecação** - encorajando você a migrar para os novos nomes
-**Nomes antigos serão removidos na v3.0.0** - então migre gradualmente
+Quatro helpers da v1 eram internos e não têm alias. Substitua-os antes de atualizar:
-**Porém**, você deve remover o uso dessas funções helper antes de atualizar:
-- `onlyNumbers` → use `string.replace(/\D/g, '')`
-- `isLastChar` → use `index === input.length - 1`
-- `generateChecksum` → agora apenas interno
-- `generateRandomNumber` → agora apenas interno
-
-## Melhorias na v2.0.0
-
-A versão 2.0.0 traz melhorias significativas em arquitetura, ferramentas e experiência do desenvolvedor:
-
-### Melhor Tree Shaking
-
-A biblioteca agora usa exports de módulos ES modernos com o campo `exports` adequado no `package.json`, permitindo melhor tree shaking em bundlers modernos. Você pode importar apenas o que precisa:
-
-```javascript
-// Apenas as funções que você importar serão incluídas no seu bundle
-import { isValidCpf, formatCpf } from '@brazilian-utils/brazilian-utils';
-```
-
-Desde a 2.4.0 cada utilitário também é um subpath próprio, então um bundler que não faz tree
-shaking (ou um `require` simples) ainda carrega um único módulo, e os poucos pesados (`getCities`,
-`getMunicipalities`, `isValidNcm`, `isValidCbo`, `isValidCnae`, `getBanks`) podem ser carregados sob
-demanda:
-
-```javascript
-import { isValidCpf } from '@brazilian-utils/brazilian-utils/is-valid-cpf'; // ~1,4 KB, 0,8 KB com gzip
-const { getCities } = await import('@brazilian-utils/brazilian-utils/get-cities'); // só quando precisar
-```
-
-Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle) para o tamanho de cada entrada.
-
-### Estrutura Mais Simples
-
-O código foi reorganizado para melhor manutenibilidade:
-- **v1**: Estrutura complexa com diretórios separados `utilities/` e `helpers/`
-- **v2**: Estrutura plana com utilitários internos no diretório `_internals/`
-- Cada utilitário é autocontido em seu próprio diretório
-- Caminhos de importação mais limpos e melhor organização do código
-
-### Ferramentas Modernas
-
-Atualizado para ferramentas modernas e mais rápidas:
-- **Build**: Migrado de `tsdx` para uma stack com **Vite+** para builds e scripts mais rápidos
-- **Testes**: Migrado de `jest` para **Vitest** (mais rápido, compatível com Jest, nativo ESM)
-- **Linting/Formatação**: Migrado de `prettier` + `eslint` para a toolchain do Vite+ (`vp fmt` e `vp check`, sobre o Oxc)
-- **TypeScript**: Configuração moderna otimizada para bundlers
-
-### Testes em Browsers
-
-Agora inclui suporte para testes cross-browser:
-- Testes rodam em browsers reais (Chrome, Firefox, Safari, Edge)
-- Garante compatibilidade entre diferentes ambientes de browser
-- Melhor confiança na funcionalidade cross-platform
-
-Execute testes em browsers com:
-```bash
-npm run test:chrome-browser
-npm run test:firefox-browser
-npm run test:safari-browser
-npm run test:edge-browser
-```
-
-### Menos Dependências
-
-Redução de dependências de desenvolvimento mantendo zero dependências de runtime:
-- **v1**: Múltiplas ferramentas (tsdx, jest, prettier, eslint, husky, lint-staged, etc.)
-- **v2**: Uma toolchain (Vite+ para build, lint, formatação e testes, com suporte de browser do Vitest via webdriverio) mais os gates de qualidade listados no CONTRIBUTING.md (Stryker, knip, jscpd, API Extractor, commitlint)
-- Manutenção mais simples e pipelines CI/CD mais rápidos
-- Zero dependências de runtime (mantido)
-
-### Novas Funções e Recursos
-
-Adicionadas novas utilitários úteis:
-- `getHolidays` - Obtém feriados brasileiros (nacionais e estaduais)
-- `getBoletoInfo` - Extrai informações de boleto (valor, vencimento, código do banco)
-- `formatPhone` - Formata números de telefone com padrões brasileiros
-- `formatBoleto` - Formata números de boleto
-- `generateBoleto` - Gera números de boleto válidos aleatórios
-- `formatPis` - Formata números de PIS
-- `isValidRenavam` - Valida RENAVAM (número de registro de veículos)
-- `isValidBankAccount` - Valida contas bancárias brasileiras com algoritmos específicos para principais bancos
-
-A 2.4.0 acrescentou muitas outras famílias a essas, todas listadas na [documentação de utilitários](pt-br/utilities.md):
-Pix (`isValidPixKey`, `generatePixPayload`, `getPixPayloadInfo`), chave de NF-e/DF-e, CNS, certidão,
-CEI/CNO/CAEPF, IBAN, número de cartão, VIN, registro profissional, consulta de bancos (`getBanks`,
-`getBankByCode`, `getBankByIspb`), códigos CBO/CNAE/NCM/CFOP/CST/CSOSN, dias úteis (`isBusinessDay`,
-`addBusinessDays`, `differenceInBusinessDays`), categorias de natureza jurídica, municípios offline
-(`getMunicipalities`, `getMunicipalityByCode`), DDD e fuso horário, número por extenso e um
-`capitalize` que conhece as designações societárias brasileiras.
-
-#### Suporte a CNPJ Alfanumérico (Versão 2)
-
-A v2.0.0 adiciona suporte ao novo formato alfanumérico de CNPJ introduzido pela Receita Federal. Tanto `isValidCnpj` quanto `generateCnpj` agora suportam CNPJs versão 2 (alfanuméricos):
-
-```javascript
-import { isValidCnpj, generateCnpj } from '@brazilian-utils/brazilian-utils';
-
-// Gerar CNPJ alfanumérico
-const alphaCnpj = generateCnpj(2); // ex: "Q0SLFMBD7VX439"
-
-// Validar CNPJ alfanumérico (requer opção de versão)
-isValidCnpj("Q0.SLF.MBD/7VX4-39", { version: 2 }); // true
-isValidCnpj("Q0SLFMBD7VX439", { version: 2 }); // true
-
-// Versão 1 (numérico) é o padrão
-isValidCnpj("12.345.678/0001-95"); // true (valida apenas numérico)
-isValidCnpj("12.345.678/0001-95", { version: 1 }); // true (explícito)
-```
-
-**Importante**: Por padrão, `isValidCnpj()` valida apenas CNPJs numéricos (versão 1). Para validar CNPJs alfanuméricos, você deve passar explicitamente `{ version: 2 }`.
-
-### Melhor Suporte TypeScript
-
-- Configuração TypeScript moderna otimizada para bundlers
-- Melhor inferência de tipos e exports
-- Experiência do desenvolvedor melhorada com melhor autocomplete
-
-## Mudanças Quebradoras
-
-### Nomes de Funções Alterados (PascalCase → camelCase)
-
-Todos os nomes de funções foram alterados de PascalCase para camelCase para seguir as convenções de nomenclatura JavaScript.
-
-**Importante: Compatibilidade com Versões Anteriores**
+| v1 | Substituto |
+|---|---|
+| `onlyNumbers(value)` | `value.replace(/\D/g, '')` |
+| `isLastChar(index, input)` | `index === input.length - 1` |
+| `generateChecksum` | Não é mais exportada. Escreva o cálculo do dígito verificador que precisar. |
+| `generateRandomNumber(length)` | Um laço próprio sobre `Math.floor(Math.random() * 10)`. |
-Para facilitar a migração, **a v2.x ainda exporta os nomes antigos em PascalCase como aliases deprecated**. Isso significa:
+## O que mudou
-- Seu código existente usando `formatCPF`, `isValidCNPJ`, etc. continuará funcionando na v2.x
-- Você receberá avisos de deprecação no seu IDE/TypeScript
-- Os nomes antigos serão **removidos na v3.0.0**
+- **Os nomes são camelCase.** Veja [Funções renomeadas](#funções-renomeadas).
+- **O tree-shaking funciona até a função**, e cada utilitário também é um subpath próprio (`@brazilian-utils/brazilian-utils/is-valid-cpf`), então os pesados podem ser carregados sob demanda. Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle).
+- **CNPJ alfanumérico.** `isValidCnpj` e `generateCnpj` aceitam o novo formato alfanumérico com `{ version: 2 }`. O numérico (versão 1) continua sendo o padrão. Veja [`generateCnpj` e a versão](#generatecnpj-e-a-versão).
+- **`getAddressInfoByCep`** aceita a opção `providers`, completa com zeros um CEP numérico e lança erros tipados: `GetAddressInfoByCepValidationError`, `GetAddressInfoByCepNotFoundError` e `GetAddressInfoByCepServiceError`. Chamadas sem opções funcionam como na v1.
+- **`getCities`** retorna a lista em ordem alfabética. Desde a 2.4.0 está descontinuada: `getMunicipalities('SP')` retorna os mesmos municípios com seus códigos IBGE, e `getMunicipalityByCode('3550308')` busca um deles offline.
+- **`isValidIe`** recebe um único objeto desde a 2.4.0, `isValidIe({ value, stateCode })`. A forma posicional está descontinuada.
+- **Muitos utilitários novos** desde a v2: feriados e dias úteis, Pix, chave de NF-e, leitura de boleto, formatação de telefone, contas bancárias e consulta de bancos, códigos de classificação (CBO, CNAE, NCM, CFOP), municípios offline, números por extenso e mais. Todos estão na [referência de utilitários](pt-br/utilities.md).
+- **As ferramentas** mudaram para Vite+ e Vitest, com testes em navegador no CI. Isso só importa para quem contribui; veja o [CONTRIBUTING.md](https://github.com/brazilian-utils/javascript/blob/main/CONTRIBUTING.md).
-**Recomendação:** Embora você possa atualizar para v2.x sem alterar seu código imediatamente, recomendamos migrar para os novos nomes em camelCase o quanto antes para se preparar para a v3.0.0.
+## Funções renomeadas
-#### Funções de Validação
+Todos os outros exports mantêm o nome da v1.
| v1 | v2 |
|---|---|
@@ -155,63 +40,15 @@ Para facilitar a migração, **a v2.x ainda exporta os nomes antigos em PascalCa
| `isValidCNPJ` | `isValidCnpj` |
| `isValidCEP` | `isValidCep` |
| `isValidPIS` | `isValidPis` |
-| `isValidIE` | `isValidIe` (desde a 2.4.0 prefira a forma objeto, `isValidIe({ value, stateCode })`; a forma posicional está descontinuada) |
-| `isValidProcessoJuridico` | `isValidProcessoJuridico` (inalterado) |
-| `isValidBoleto` | `isValidBoleto` (inalterado) |
-| `isValidEmail` | `isValidEmail` (inalterado) |
-| `isValidPhone` | `isValidPhone` (inalterado) |
-| `isValidMobilePhone` | `isValidMobilePhone` (inalterado) |
-| `isValidLandlinePhone` | `isValidLandlinePhone` (inalterado) |
-| `isValidLicensePlate` | `isValidLicensePlate` (inalterado) |
-| `isValidRenavam` | `isValidRenavam` (novo) |
-
-#### Funções de Formatação
-
-| v1 | v2 |
-|---|---|
+| `isValidIE` | `isValidIe` |
| `formatCPF` | `formatCpf` |
| `formatCNPJ` | `formatCnpj` |
| `formatCEP` | `formatCep` |
-| `formatProcessoJuridico` | `formatProcessoJuridico` (inalterado) |
-| `formatBoleto` | `formatBoleto` (inalterado) |
-| `formatCurrency` | `formatCurrency` (inalterado) |
-| `formatPhone` | `formatPhone` (novo) |
-
-#### Funções de Geração
-
-| v1 | v2 |
-|---|---|
| `generateCPF` | `generateCpf` |
| `generateCNPJ` | `generateCnpj` |
-| `generateBoleto` | `generateBoleto` (inalterado) |
-
-**Nota sobre o comportamento do `generateCnpj`:**
-Na v2.x, `generateCnpj()` sem argumentos retorna por padrão a versão 1 (CNPJ numérico). Na v3.0.0, este comportamento mudará para selecionar aleatoriamente entre versão 1 (numérico) e versão 2 (alfanumérico) para melhor aleatoriedade. Se você precisa de uma versão específica, sempre passe o parâmetro de versão explicitamente:
+Antes (v1):
-```javascript
-// Recomendado: Sempre especifique a versão
-generateCnpj(1); // Sempre gera CNPJ numérico
-generateCnpj(2); // Sempre gera CNPJ alfanumérico
-
-// Não recomendado: Depender do comportamento padrão
-generateCnpj(); // Atualmente gera numérico (v1), mas será aleatório na v3.0.0
-```
-
-#### Outras Funções
-
-| v1 | v2 |
-|---|---|
-| `parseCurrency` | `parseCurrency` (inalterado) |
-| `capitalize` | `capitalize` (inalterado) |
-| `getStates` | `getStates` (inalterado) |
-| `getCities` | `getCities` (inalterado; descontinuado na 2.4.0 em favor de `getMunicipalities`) |
-| `getMunicipality` | `getMunicipality` (descontinuado na 2.4.0 em favor de `getMunicipalityByCode`, que é síncrono e offline) |
-| `getAddressInfoByCep` | `getAddressInfoByCep` (API alterada, veja abaixo) |
-
-### Exemplo de Migração
-
-**Antes (v1):**
```javascript
import { isValidCPF, formatCPF, generateCNPJ } from '@brazilian-utils/brazilian-utils';
@@ -220,7 +57,8 @@ const formatted = formatCPF('12345678909');
const cnpj = generateCNPJ();
```
-**Depois (v2):**
+Depois (v2):
+
```javascript
import { isValidCpf, formatCpf, generateCnpj } from '@brazilian-utils/brazilian-utils';
@@ -229,176 +67,25 @@ const formatted = formatCpf('12345678909');
const cnpj = generateCnpj();
```
-### Funções Helper Removidas
-
-As seguintes funções helper não são mais exportadas na API pública. Estas eram utilitários internos que não deveriam ter sido expostos.
-
-**Nota:** Diferentemente das funções renomeadas acima, esses helpers **NÃO** possuem aliases de compatibilidade. Você deve migrar para longe deles antes de atualizar para a v2.x.
+### `generateCnpj` e a versão
-#### `onlyNumbers`
-Esta função foi removida da API pública. Agora é um utilitário interno chamado `sanitizeToDigits`.
+`generateCnpj()` sem argumentos gera um CNPJ numérico na v2.x. Na v3.0.0 vai sortear entre numérico e alfanumérico, então passe a versão quando precisar de uma específica:
-**Migração:**
```javascript
-// v1 - Não use mais isso
-import { onlyNumbers } from '@brazilian-utils/brazilian-utils';
-const digits = onlyNumbers('123-456');
-
-// v2 - Use uma substituição simples
-const digits = '123-456'.replace(/\D/g, '');
+generateCnpj(1); // sempre numérico
+generateCnpj(2); // sempre alfanumérico, ex.: "Q0SLFMBD7VX439"
+generateCnpj(); // numérico hoje, aleatório na v3.0.0
```
-#### `isLastChar`
-Esta função foi removida. Use uma comparação inline simples.
+`isValidCnpj` valida CNPJs numéricos por padrão. Para validar alfanuméricos, passe `{ version: 2 }`:
-**Migração:**
```javascript
-// v1 - Não use mais isso
-import { isLastChar } from '@brazilian-utils/brazilian-utils';
-if (isLastChar(index, input)) { /* ... */ }
-
-// v2 - Use comparação inline
-if (index === input.length - 1) { /* ... */ }
+isValidCnpj('12.345.678/0001-95'); // true
+isValidCnpj('Q0.SLF.MBD/7VX4-39', { version: 2 }); // true
+isValidCnpj('Q0.SLF.MBD/7VX4-39'); // false (só numérico sem a opção)
```
-#### `generateChecksum`
-Esta função agora é interna e não é mais exportada na API pública. O pacote não exporta internals: `dist/_internals` não é publicado e não existe subpath para ele, então não há forma suportada de importar essa função na v2. Calcule o dígito verificador que você precisa no seu próprio código.
-
-**Migração:**
-```javascript
-// v1 - Não use mais isso
-import { generateChecksum } from '@brazilian-utils/brazilian-utils';
-```
-
-#### `generateRandomNumber`
-Esta função agora é interna e não é mais exportada na API pública.
-
-**Migração:**
-```javascript
-// v1 - Não use mais isso
-import { generateRandomNumber } from '@brazilian-utils/brazilian-utils';
-
-// v2 - Use sua própria implementação
-function generateRandomNumber(length) {
- let result = '';
- for (let i = 0; i < length; i++) {
- result += Math.floor(Math.random() * 10).toString();
- }
- return result;
-}
-```
-
-## Novas Funções
-
-As seguintes funções são novas na v2.0.0:
-
-### `getHolidays`
-
-Obtém feriados brasileiros para um determinado ano. Suporta feriados nacionais e estaduais.
-
-```javascript
-import { getHolidays } from '@brazilian-utils/brazilian-utils';
-
-// Obtém todos os feriados nacionais
-const holidays = getHolidays(2024);
-
-// Obtém feriados para um estado específico
-const spHolidays = getHolidays({ year: 2024, stateCode: 'SP' });
-```
-
-### `getBoletoInfo`
-
-Extrai informações de um boleto (valor, data de vencimento, código do banco).
-
-```javascript
-import { getBoletoInfo } from '@brazilian-utils/brazilian-utils';
-
-const info = getBoletoInfo('00190000090114971860168524522114675860000102656');
-// { amount: 102656, expirationDate: Date, bankCode: '001' }
-```
-
-### `formatPhone`
-
-Formata números de telefone de acordo com padrões brasileiros.
-
-```javascript
-import { formatPhone } from '@brazilian-utils/brazilian-utils';
-
-formatPhone('11900000000'); // 11900-0000 (CUIDADO: a máscara padrão "sn" trunca um número com DDD)
-formatPhone('11900000000', { mask: 'nanp' }); // (11) 90000-0000
-formatPhone('11900000000', { mask: 'auto' }); // (11) 90000-0000
-```
-
-### `isValidRenavam`
-
-Valida RENAVAM (Registro Nacional de Veículos Automotores). Suporta tanto o formato antigo (9 dígitos) quanto o novo formato (11 dígitos).
-
-```javascript
-import { isValidRenavam } from '@brazilian-utils/brazilian-utils';
-
-isValidRenavam('639884962'); // true (9 dígitos, formato antigo)
-isValidRenavam('00639884962'); // true (11 dígitos, formato novo)
-isValidRenavam('12345678901'); // false (checksum inválido)
-```
-
-### `isValidBankAccount`
-
-Valida contas bancárias brasileiras. Suporta algoritmos de validação específicos para os principais bancos (Banco do Brasil, Itaú, Bradesco, Santander, Caixa Econômica Federal) e validação genérica mod10/mod11 para outros bancos.
-
-```javascript
-import { isValidBankAccount } from '@brazilian-utils/brazilian-utils';
-
-// Banco do Brasil
-isValidBankAccount({
- bankCode: '001',
- agency: '1584',
- account: '00210169',
- digit: '6'
-}); // true
-
-// Itaú
-isValidBankAccount({
- bankCode: '341',
- agency: '2545',
- account: '02366',
- digit: '1'
-}); // true
-
-// Outros bancos usam validação genérica
-isValidBankAccount({
- bankCode: '246',
- agency: '1234',
- account: '123456',
- digit: '6'
-}); // true (o dígito corresponde ao mod10)
-```
-
-## Mudanças na API
-
-### `getAddressInfoByCep`
-
-A função `getAddressInfoByCep` agora suporta opções adicionais e melhor tratamento de erros.
-
-**Antes (v1):**
-```javascript
-const address = await getAddressInfoByCep('01310100');
-```
-
-**Depois (v2):**
-```javascript
-// Ainda funciona da mesma forma
-const address = await getAddressInfoByCep('01310100');
-
-// Mas agora suporta opções
-const address = await getAddressInfoByCep('01310-100', {
- providers: ['viacep', 'brasilapi']
-});
-
-// Também aceita números (será preenchido automaticamente com zeros à esquerda)
-const address = await getAddressInfoByCep(1310100);
-```
-
-A função agora exporta classes de erro para melhor tratamento de erros:
+### Erros de `getAddressInfoByCep`
```javascript
import {
@@ -412,58 +99,28 @@ try {
const address = await getAddressInfoByCep('01310100');
} catch (error) {
if (error instanceof GetAddressInfoByCepValidationError) {
- // Tratar erro de validação
+ // CEP inválido
} else if (error instanceof GetAddressInfoByCepNotFoundError) {
- // Tratar erro de não encontrado
+ // nenhum endereço para este CEP
} else if (error instanceof GetAddressInfoByCepServiceError) {
- // Tratar erro de serviço
+ // os provedores falharam
}
}
```
-### `getCities`
-
-A função `getCities` agora retorna resultados ordenados alfabeticamente.
-
-**Antes (v1):**
-```javascript
-getCities(); // Retornava array não ordenado
-getCities('SP'); // Retornava array não ordenado
-```
-
-**Depois (v2):**
-```javascript
-getCities(); // Retorna ordenado alfabeticamente
-getCities('SP'); // Retorna ordenado alfabeticamente
-```
-
-**Desde a 2.4.0:** `getCities` está descontinuado. `getMunicipalities('SP')` retorna os mesmos municípios
-com o código do IBGE (`{ code, name, stateCode }`), e `getMunicipalityByCode('3550308')` busca um deles
-sem chamada de rede.
-
-## Checklist de Migração
-
-### Obrigatório (antes de atualizar para v2.x)
-- [ ] Remover uso de funções helper (`onlyNumbers`, `isLastChar`, `generateChecksum`, `generateRandomNumber`)
+## Checklist
-### Opcional (recomendado antes da v3.0.0)
-- [ ] Atualizar todas as importações para usar nomes de funções em camelCase
-- [ ] Substituir todas as chamadas de funções com nomes em camelCase
-- [ ] Trocar `getCities` por `getMunicipalities` e `getMunicipality` por `getMunicipalityByCode` (descontinuados na 2.4.0)
-- [ ] Chamar `isValidIe({ value, stateCode })` em vez de `isValidIe(stateCode, ie)` (descontinuado na 2.4.0)
-- [ ] Importar os tipos `*Params` em vez dos aliases `*Options` mantidos para as funções de um único argumento objeto (descontinuados na 2.4.0)
-- [ ] Tirar `'widenet'` dos `providers` do `getAddressInfoByCep` (o serviço acabou; descontinuado na 2.4.0)
+Obrigatório antes de atualizar:
-### Revisar se aplicável
-- [ ] Atualizar tratamento de erros para `getAddressInfoByCep` se necessário
-- [ ] Revisar uso de `getCities` se a ordenação era importante
-- [ ] Testar todas as funções de validação e formatação
-- [ ] Atualizar importações de tipos TypeScript se aplicável
+- [ ] Substituir `onlyNumbers`, `isLastChar`, `generateChecksum` e `generateRandomNumber`.
-## Obter Ajuda
+Recomendado antes da v3.0.0:
-Se você encontrar problemas durante a migração, por favor:
+- [ ] Renomear os imports e as chamadas da tabela acima para camelCase.
+- [ ] Trocar `getCities` por `getMunicipalities` e `getMunicipality` por `getMunicipalityByCode`.
+- [ ] Chamar `isValidIe({ value, stateCode })` em vez de `isValidIe(stateCode, ie)`.
+- [ ] Importar os tipos `*Params` em vez dos aliases `*Options` das funções que recebem um único objeto.
+- [ ] Tirar `'widenet'` dos `providers` de `getAddressInfoByCep` (o serviço não existe mais).
+- [ ] Passar a versão para `generateCnpj` quando precisar de uma específica.
-1. Verifique a [documentação de utilitários](/pt-br/utilities.md) para as assinaturas corretas das funções
-2. Revise os exemplos neste guia de migração
-3. Abra uma issue no [repositório GitHub](https://github.com/brazilian-utils/javascript) se encontrar um bug
+Encontrou um bug na migração? [Abra uma issue](https://github.com/brazilian-utils/javascript/issues).
diff --git a/docs/pt-br/utilities.html b/docs/pt-br/utilities.html
index 383835487..6e278741b 100644
--- a/docs/pt-br/utilities.html
+++ b/docs/pt-br/utilities.html
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/pt-br/utilities.md b/docs/pt-br/utilities.md
index 22503866e..d91710273 100644
--- a/docs/pt-br/utilities.md
+++ b/docs/pt-br/utilities.md
@@ -4,13 +4,27 @@ description: "Todos os utilitários do Brazilian Utils, agrupados por família (
keywords: ["CPF", "CNPJ", "CEP", "boleto", "Pix", "NF-e", "telefone", "placa", "RENAVAM", "PIS", "CNH", "IBAN", "feriados", "dias úteis", "CBO", "CNAE", "NCM", "CFOP", "validador", "formatador", "parser", "gerador"]
---
-Aqui você encontrará todos os utilitários disponíveis para uso.
+Todas as funções do pacote, agrupadas por família. Cada seção diz o que a função faz, quais são as opções, o que ela retorna com entrada inválida e mostra um exemplo.
+
+## Convenções
+
+Estas regras valem para todas as funções, a não ser que a seção diga o contrário.
+
+- **Nada lança erro com entrada inválida** (`null`, `undefined`, tipo errado): `isValid*` retornam `false`, `format*` e `parse*` retornam `''`, `get*` de um item retornam `null`, `get*` de lista retornam `[]`. As únicas exceções são as assíncronas `getAddressInfoByCep` e `getCepInfoByAddress`, que rejeitam com erros tipados.
+- **Validadores aceitam o valor com ou sem máscara**: os caracteres de máscara usuais (`.`, `-`, `/`) e espaços entre ou ao redor dos grupos são ignorados, então não é preciso limpar a formatação antes.
+- **Formatadores aplicam a máscara até onde o valor vai**, então também servem como máscara de digitação. As funções `parse*` fazem o inverso e mantêm só os caracteres que importam.
+- **Geradores usam `Math.random()`**, então servem para testes e dados de exemplo e nunca para nada relacionado a segurança.
+- **Getters retornam um array ou objeto novo a cada chamada**, então alterar um resultado nunca afeta a chamada seguinte.
+- **Todas as funções são síncronas**, exceto `getAddressInfoByCep`, `getCepInfoByAddress` e a descontinuada `getMunicipality`.
+
## CPF
### isValidCpf
-Valida se o CPF é válido. Aceita os caracteres de máscara usuais e espaços em branco entre/ao redor dos grupos.
+Valida um CPF.
+
+- Retorna `false` para um número reservado (todos os dígitos iguais, como `00000000000`) e para um dígito verificador errado.
```javascript
import { isValidCpf } from '@brazilian-utils/brazilian-utils';
@@ -21,7 +35,10 @@ isValidCpf('111 444 777 35'); // true (máscara com espaços)
### formatCpf
-Formata o CPF. `options.pad` (parte de `FormatCpfOptions`) preenche o valor com zeros à esquerda até as 11 posições do padrão antes de aplicar a máscara (padrão `false`). `options.obfuscate` (do mesmo tipo) esconde os 3 primeiros dígitos e os 2 dígitos verificadores (`***.456.789-**`), a convenção de exibição do gov.br / Receita Federal, aplicada após o `pad`. É lida por veracidade (truthiness), do mesmo jeito que o `pad`, então qualquer valor verdadeiro esconde os dígitos.
+Formata um CPF.
+
+- **Opções** (`FormatCpfOptions`): `pad` preenche o valor com zeros à esquerda até 11 dígitos antes de aplicar a máscara (padrão `false`); `obfuscate` esconde os 3 primeiros dígitos e os 2 dígitos verificadores.
+- `obfuscate` é aplicada após o `pad`.
```javascript
import { formatCpf } from '@brazilian-utils/brazilian-utils';
@@ -43,7 +60,10 @@ parseCpf('746.506.880-00'); // 74650688000
### generateCpf
-Gera um CPF válido aleatório. Usa `Math.random()` internamente, então não é criptograficamente seguro. O argumento opcional `state` (tipado como `StateCode`, os códigos de duas letras dos 27 estados brasileiros, ex. `"SP"`, `"MG"`) vincula o CPF a um estado fixando o dígito da região fiscal na 9ª posição ao código desse estado. Omitido, uma região aleatória é usada. Um código desconhecido sorteia um dígito de região fiscal aleatório em vez de lançar erro, então o resultado continua sendo um CPF válido.
+Gera um CPF válido aleatório.
+
+- O argumento opcional `state` (`StateCode`, ex. `"SP"`) fixa o dígito da região fiscal (o 9º) no código desse estado.
+- Sem `state`, ou com um código desconhecido, um dígito de região fiscal aleatório é sorteado.
```javascript
import { generateCpf } from '@brazilian-utils/brazilian-utils'
@@ -53,11 +73,16 @@ generateCpf('SP'); // o 9º dígito é 8, o código da região fiscal de SP
generateCpf('MG'); // o 9º dígito é 6, o código da região fiscal de MG
```
+Fonte: [Receita Federal, "Cadastros: CPF e CNPJ"](https://www.gov.br/receitafederal/pt-br/assuntos/educacao-fiscal/educacao_fiscal/folhetos-orientativos/cadastros-dig.pdf).
+
## CNPJ
### isValidCnpj
-Valida se o CNPJ é válido. `options.version` (parte de `IsValidCnpjOptions`) escolhe qual formato é aceito: `1` (padrão) apenas o formato numérico, `2` tanto o numérico quanto o alfanumérico; qualquer outro valor é lido como `1`, do mesmo jeito que `formatCnpj` e `parseCnpj` o leem. Os caracteres de máscara usuais e espaços em branco são aceitos nas duas versões. A versão `2` não tem lista de valores reservados, porque o manual da Receita Federal não define nenhuma para o formato alfanumérico: uma base alfanumérica de caracteres repetidos (todos `A`, por exemplo) que passe no dígito verificador é aceita, enquanto os números reservados numéricos são rejeitados na versão `1`.
+Valida um CNPJ.
+
+- **Opções** (`IsValidCnpjOptions`): `version` escolhe o formato aceito: `1` (padrão) apenas numérico, `2` numérico e alfanumérico. Qualquer outro valor é lido como `1`.
+- Um número reservado (todos os dígitos iguais) é rejeitado nas duas versões; a versão `2` não tem lista de reservados para letras.
```javascript
import { isValidCnpj } from '@brazilian-utils/brazilian-utils';
@@ -66,9 +91,15 @@ isValidCnpj('15515147234255'); // false
isValidCnpj('q0slfmbd7vx439', { version: 2 }); // true (alfanumérico minúsculo)
```
+Fonte: [Receita Federal, Manual do DV do CNPJ](https://www.gov.br/receitafederal/pt-br/centrais-de-conteudo/publicacoes/documentos-tecnicos/cnpj/manual-dv-cnpj.pdf), [CNPJ alfanumérico](https://www.gov.br/receitafederal/pt-br/acesso-a-informacao/acoes-e-programas/programas-e-atividades/cnpj-alfanumerico).
+
### formatCnpj
-Formata o CNPJ. `options.pad` (parte de `FormatCnpjOptions`) preenche o valor com zeros à esquerda até as 14 posições do padrão antes de aplicar a máscara (padrão `false`). `options.version` (do mesmo tipo) escolhe qual formato de CNPJ é lido: `1` (padrão) apenas numérico, `2` alfanumérico. `options.obfuscate` esconde os 2 primeiros dígitos e os 2 dígitos verificadores (`**.345.678/0001-**`), a convenção de exibição do gov.br / Receita Federal. Vale para as duas versões, é aplicada após o `pad` e é lida por veracidade (truthiness), do mesmo jeito que o `pad`, então qualquer valor verdadeiro esconde os dígitos.
+Formata um CNPJ.
+
+- **Opções** (`FormatCnpjOptions`): `pad` preenche o valor com zeros à esquerda até 14 caracteres antes de aplicar a máscara (padrão `false`); `version` escolhe o formato, `1` (padrão) apenas numérico, `2` alfanumérico; `obfuscate` esconde os 2 primeiros dígitos e os 2 dígitos verificadores.
+- A versão `2` mantém letras (em maiúsculas) e dígitos; a versão `1` mantém apenas dígitos.
+- `obfuscate` vale para as duas versões e é aplicada após o `pad`.
```javascript
import { formatCnpj } from '@brazilian-utils/brazilian-utils';
@@ -81,7 +112,9 @@ formatCnpj('12345678000195', { obfuscate: true }); // **.345.678/0001-**
### parseCnpj
-Remove a formatação do CNPJ, retorna um valor normalizado e limita o resultado a 14 caracteres. `options.version` (parte de `ParseCnpjOptions`) escolhe qual formato de CNPJ é normalizado: `1` (padrão) mantém apenas dígitos, `2` mantém letras e dígitos, de modo que um CNPJ alfanumérico sobrevive à ida e volta.
+Remove a formatação do CNPJ, retorna um valor normalizado e limita o resultado a 14 caracteres.
+
+- **Opções** (`ParseCnpjOptions`): `version` escolhe o formato: `1` (padrão) mantém apenas dígitos, `2` mantém letras e dígitos, em maiúsculas.
```javascript
import { parseCnpj } from '@brazilian-utils/brazilian-utils';
@@ -92,7 +125,10 @@ parseCnpj('12.OUT.345/0001-99', { version: 2 }); // 12OUT345000199
### generateCnpj
-Gera um CNPJ válido aleatório. Usa `Math.random()` internamente, então não é criptograficamente seguro. O primeiro argumento é a versão, como antes, ou um objeto `GenerateCnpjParams` com a mesma `version` mais `branch`, o bloco do "número de ordem" (filial) nas posições 9 a 12: um inteiro de 1 a 9999 escrito com zeros à esquerda em quatro caracteres, aleatório por padrão. Um `branch` inválido é ignorado e um bloco aleatório é usado, e o bloco continua numérico na versão alfanumérica.
+Gera um CNPJ válido aleatório.
+
+- O primeiro argumento é a versão, `1` (padrão) numérico ou `2` alfanumérico, ou um objeto `GenerateCnpjParams` com `version` mais `branch`.
+- `branch` é o bloco do "número de ordem" (filial), um inteiro de 1 a 9999 (aleatório por padrão). Um `branch` inválido é ignorado. O bloco continua numérico nas duas versões.
```javascript
import { generateCnpj } from '@brazilian-utils/brazilian-utils'
@@ -107,7 +143,10 @@ generateCnpj({ version: 2, branch: 1 }); // CNPJ alfanumérico cujo bloco de ord
### isValidCep
-Valida se o CEP ([código de endereçamento postal](https://pt.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)) é válido. Aceita entrada como `string` ou `number`, mas um CEP que começa com `0` precisa ser passado como string, já que um número não preserva o zero à esquerda (`isValidCep(1310100)` é `false`, `isValidCep('01310100')` é `true`); espaços, pontos e hífens ao redor/entre os 8 dígitos são ignorados, mas qualquer outro caractere, uma letra em especial, invalida o valor.
+Valida um CEP ([código de endereçamento postal](https://pt.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)).
+
+- Aceita `string` ou `number`. Um CEP que começa com `0` precisa ser string, já que um número não preserva o zero à esquerda.
+- Espaços, pontos e hífens são ignorados. Qualquer outro caractere invalida o valor.
```javascript
import { isValidCep } from '@brazilian-utils/brazilian-utils';
@@ -123,7 +162,10 @@ isValidCep('12345'); // false (tamanho inválido)
### formatCep
-Formata o CEP ([código de endereçamento postal](https://pt.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)). `options.pad` (parte de `FormatCepOptions`) completa o valor com zeros à esquerda até os 8 dígitos antes de aplicar a máscara (padrão `false`); um CEP que começa com `0` passado como número perde esse zero, então passe-o como string ou use `pad`.
+Formata um CEP ([código de endereçamento postal](https://pt.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)).
+
+- **Opções** (`FormatCepOptions`): `pad` preenche o valor com zeros à esquerda até 8 dígitos antes de aplicar a máscara (padrão `false`).
+- Um CEP que começa com `0` passado como número perde esse zero: passe uma string ou use `pad`.
```javascript
import { formatCep } from '@brazilian-utils/brazilian-utils';
@@ -144,7 +186,7 @@ parseCep('92500-000'); // 92500000
### generateCep
-Gera um CEP aleatório. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um CEP aleatório. Um CEP não tem dígito verificador, então toda string de 8 dígitos é estruturalmente válida.
```javascript
import { generateCep } from '@brazilian-utils/brazilian-utils';
@@ -154,7 +196,13 @@ generateCep(); // '92500000'
### getAddressInfoByCep
-Busca informações de endereço para um CEP usando múltiplos provedores. O padrão é `['viacep', 'brasilapi']`. O provedor `'widenet'` está descontinuado (seu endpoint não responde mais) e foi excluído da lista padrão, mas ainda pode ser solicitado explicitamente via `options.providers` (tipado como `CepProvider[]`). O endereço retornado é tipado como `AddressInfo`. Uma falha transitória de rede é repetida duas vezes por provedor, com backoff linear de 250 ms (250 ms e depois 500 ms), então um provedor que continua falhando é tentado até 3 vezes e acrescenta cerca de 750 ms antes de a sua própria falha se concretizar; um status de erro HTTP ou uma falha não recuperável não é repetida. Os provedores são disparados juntos e disputados com `Promise.any`, não consultados um após o outro, então essas tentativas não atrasam nada para os demais provedores, apenas o momento em que uma rejeição por falha de todos pode aparecer. Um `options.providers` que não nomeia nenhum provedor conhecido rejeita com `GetAddressInfoByCepValidationError` ("Nenhum provedor válido especificado"): um array vazio, um array de nomes desconhecidos e um valor que não é um array, incluindo `null`. Com `providers: ['brasilapi']`, um CEP que a BrasilAPI não conhece rejeita com `GetAddressInfoByCepNotFoundError`, já que a BrasilAPI sinaliza a ausência com HTTP 404; qualquer outro status de erro continua sendo um `GetAddressInfoByCepServiceError`. Os três estendem `GetAddressInfoByCepError`, a classe base de todos os erros com que este utilitário rejeita, então um único `catch` nela cobre todos.
+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.
+- 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.
+- Os três estendem `GetAddressInfoByCepError`, então um único `catch` cobre todos.
```javascript
import { getAddressInfoByCep } from '@brazilian-utils/brazilian-utils';
@@ -174,7 +222,12 @@ const addressFromNumber = await getAddressInfoByCep(1310100);
### getCepInfoByAddress
-Busca CEPs a partir de um endereço usando a ViaCEP. Lança `GetCepInfoByAddressValidationError` quando a UF, a cidade ou a rua estão ausentes/inválidas — inclusive quando o argumento não é um objeto (omitido, `null`, uma string) e quando `federalUnit` não é uma string, casos em que nenhum `TypeError` cru escapa — `GetCepInfoByAddressNotFoundError` quando nenhum endereço corresponde à busca, e `GetCepInfoByAddressError` quando a própria ViaCEP responde com um status de erro HTTP. Uma requisição que não pode ser realizada (falha de transporte) rejeita com o erro original do `fetch`. Cada item é tipado como `CepAddressInfo` e traz a resposta da ViaCEP sem alterações, com os nomes de campo da própria ViaCEP: `cep`, `logradouro`, `complemento`, `unidade`, `bairro`, `localidade`, `uf`, `estado`, `regiao`, `ibge`, `gia`, `ddd` e `siafi`. Um nome de rua abrangente corresponde a muitos CEPs, então busque de forma tão específica quanto o endereço permitir.
+Busca os CEPs de um endereço na ViaCEP. Resolve com um array de `CepAddressInfo`.
+
+- O argumento (`GetCepInfoByAddressParams`) traz `federalUnit`, `city` e `street`. `federalUnit` pode estar em minúsculas; `city` e `street` têm os espaços nas pontas removidos e os acentos retirados antes da consulta.
+- Rejeita com `GetCepInfoByAddressValidationError` quando a UF, a cidade ou a rua está ausente ou inválida, com `GetCepInfoByAddressNotFoundError` quando nenhum endereço corresponde à busca, e com `GetCepInfoByAddressError` quando a ViaCEP responde com um status de erro HTTP.
+- Repete falhas transitórias de rede, como `getAddressInfoByCep`.
+- Cada item traz a resposta da ViaCEP sem alterações, com os nomes de campo da própria ViaCEP.
```javascript
import { getCepInfoByAddress } from '@brazilian-utils/brazilian-utils';
@@ -208,7 +261,10 @@ const ceps = await getCepInfoByAddress({
### isValidBoleto
-Valida se o boleto ([meio de pagamento brasileiro](https://pt.wikipedia.org/wiki/Boleto_banc%C3%A1rio)) é válido. Suporta tanto o boleto de "cobrança bancária" de 47 dígitos quanto o "boleto de arrecadação" (convênio/tributos): seja a linha digitável de 48 dígitos, seja o código de barras de 44 dígitos, ambos iniciados com `8`. Uma tolerância é mantida desde a 2.3.0: o código de moeda na posição 4 do código de barras da cobrança bancária não é verificado, embora a Carta-Circular BCB nº 2.926/2000 o fixe em `9` (real), então um boleto com qualquer outro dígito de moeda continua válido.
+Valida um boleto ([meio de pagamento brasileiro](https://pt.wikipedia.org/wiki/Boleto_banc%C3%A1rio)).
+
+- Aceita a linha digitável de 47 dígitos da "cobrança bancária" e, do "boleto de arrecadação", seja a linha digitável de 48 dígitos, seja o código de barras de 44 dígitos.
+- O código de moeda (posição 4 do código de barras da cobrança bancária) não é verificado.
```javascript
import { isValidBoleto } from '@brazilian-utils/brazilian-utils';
@@ -217,9 +273,14 @@ isValidBoleto('00190000090114971860168524522114675860000102656'); // true
isValidBoleto('846100000005246100291102005460339004695895061080'); // true (boleto de arrecadação)
```
+Fonte: [Carta-Circular BCB nº 2.926/2000](https://www.bcb.gov.br/pre/normativos/c_circ/2000/pdf/c_circ_2926_v1_O.pdf), [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
### formatBoleto
-Formata um número de boleto. `options.pad` (parte de `FormatBoletoOptions`) preenche o valor com zeros à esquerda até o número de posições do padrão antes de aplicar a máscara (padrão `false`). A máscara de arrecadação (convênio/tributos) só se aplica à linha digitável de 48 dígitos que começa com `8`; o código de barras de arrecadação de 44 dígitos não tem agrupamento de exibição definido pela FEBRABAN e mantém a máscara de "cobrança bancária".
+Formata um número de boleto.
+
+- **Opções** (`FormatBoletoOptions`): `pad` preenche o valor com zeros à esquerda até o tamanho do padrão antes de aplicar a máscara (padrão `false`).
+- Uma linha digitável de 48 dígitos que começa com `8` recebe a máscara de arrecadação: quatro blocos de 11 dígitos, cada um seguido do seu dígito verificador. O código de barras de arrecadação de 44 dígitos mantém a máscara de "cobrança bancária".
```javascript
import { formatBoleto } from '@brazilian-utils/brazilian-utils';
@@ -230,6 +291,8 @@ formatBoleto('846100000005246100291102005460339004695895061080'); // 84610000000
formatBoleto('84610000000246100291100054603390069589506108'); // 84610.00000 02461.002911 00054.603390 0 69589506108 (código de barras de arrecadação de 44 dígitos mantém a máscara bancária)
```
+Fonte: [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
### parseBoleto
Remove a formatação do boleto, mantém apenas os dígitos e limita o resultado a 47 dígitos (48 para boleto de arrecadação).
@@ -242,7 +305,9 @@ parseBoleto('00190.00009 01149.718601 68524.522114 6 75860000102656'); // 001900
### generateBoleto
-Gera um boleto válido aleatório. Informe `{ type: "arrecadacao" }` (tipado como `GenerateBoletoParams`) para gerar um boleto de arrecadação em vez do tipo padrão "bancario" (cobrança bancária). Um boleto de arrecadação sorteia o segmento entre 1 e 7 (o segmento 9 é de uso dos próprios bancos) e o identificador de valor entre os quatro valores possíveis, `6` e `8` para valor efetivo e `7` e `9` para quantidade de referência, de modo que os dois ramos de `hasEffectiveValue` do `getBoletoInfo` sejam alcançáveis.
+Gera um boleto válido aleatório.
+
+- Informe `{ type: 'arrecadacao' }` (`GenerateBoletoParams`) para um boleto de arrecadação de 48 dígitos em vez do tipo padrão `'bancario'` (cobrança bancária, 47 dígitos).
```javascript
import { generateBoleto } from '@brazilian-utils/brazilian-utils';
@@ -253,7 +318,12 @@ generateBoleto({ type: 'arrecadacao' }); // "84610000000524610029110200546033900
### getBoletoInfo
-Extrai informações de um boleto (valor, data de vencimento, código do banco). Retorna `null` quando `value` não é um boleto válido — o `isValidBoleto` é verificado antes —, então o resultado precisa ser estreitado antes de ser lido. A 2.3.0 retornava `undefined` aqui; agora todo getter do pacote responde com `null` a uma busca que não resolve, então só uma comparação estrita `=== undefined` é afetada. Aceita opcionalmente `{ referenceDate }` (tipado como `GetBoletoInfoOptions`) para resolver o ciclo do "fator de vencimento" a partir de uma data específica em vez de agora (o ciclo de data-base do fator reiniciou em 22/02/2025, segundo a FEBRABAN). Nem a FEBRABAN nem o Banco Central publicam uma forma de distinguir um fator do ciclo antigo de um do ciclo novo, então todo fator resolve para uma de duas datas separadas por 9000 dias e o `referenceDate` escolhe entre elas por meio das janelas de segurança da própria biblioteca: o mesmo boleto pode passar a resolver para a outra candidata com o tempo, então informe `referenceDate` explicitamente sempre que a resposta precisar ser estável. A busca de ciclo nunca desce abaixo do primeiro ciclo, então um `referenceDate` anterior ao próprio esquema ainda resolve um fator para a data mais antiga que aquele fator consegue representar, em vez de uma anterior à data-base de 07/10/1997. Para um boleto de arrecadação, o resultado, tipado como `BoletoInfo`, continua trazendo as duas chaves, porém vazias, `bankCode: ''` e `expirationDate: null`, já que o boleto não tem código de banco nem fator de vencimento, e acrescenta `type: "arrecadacao"`, `segment`, `value` e `hasEffectiveValue`.
+Extrai informações de um boleto (valor, data de vencimento, código do banco). Retorna `null` quando o valor não é um boleto válido.
+
+- **Opções** (`GetBoletoInfoOptions`): `referenceDate` resolve o ciclo do "fator de vencimento" a partir dessa data em vez de agora.
+- Retorna um `BoletoInfo`: `amount` em centavos, `expirationDate` e o `bankCode` de três dígitos. `expirationDate` é `null` quando o boleto não traz fator de vencimento (um fator abaixo de `1000`).
+- O ciclo do fator de vencimento reiniciou em 22/02/2025, então um fator pode significar uma de duas datas separadas por 9000 dias. `referenceDate` escolhe entre elas; informe-a sempre que a resposta precisar ser estável.
+- Um boleto de arrecadação tem `bankCode: ''` e `expirationDate: null`, mais `type: 'arrecadacao'`, `segment`, `value` (o valor em reais) e `hasEffectiveValue`.
```javascript
import { getBoletoInfo } from '@brazilian-utils/brazilian-utils';
@@ -264,7 +334,7 @@ getBoletoInfo('00190000090114971860168524522114675860000102656');
getBoletoInfo('00190000090114971860168524522114675860000102656', {
referenceDate: new Date(2018, 6, 1)
});
-// Resolve o ciclo do fator de vencimento a partir de 2018-07-01
+// Resolve o ciclo do fator de vencimento a partir de 01/07/2018
getBoletoInfo('846100000005246100291102005460339004695895061080');
// { amount: 2461, expirationDate: null, bankCode: '', type: 'arrecadacao', segment: 4, value: 24.61, hasEffectiveValue: true }
@@ -272,11 +342,16 @@ getBoletoInfo('846100000005246100291102005460339004695895061080');
getBoletoInfo('invalid'); // null
```
+Fonte: [Carta-Circular BCB nº 2.926/2000](https://www.bcb.gov.br/pre/normativos/c_circ/2000/pdf/c_circ_2926_v1_O.pdf), [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
## Pix
### isValidPixKey
-Valida se uma chave Pix é válida: um CPF, um CNPJ, um e-mail, um telefone celular brasileiro ou uma chave aleatória (EVP), conforme os formatos de chave do DICT. O manual registra um "número de telefone celular", então um telefone fixo não é uma chave Pix válida. `options.accept` (tipado como `IsValidPixKeyOptions`) restringe quais tipos de chave são aceitos; o padrão é aceitar todos, e `[]` rejeita todos. Exporta o tipo `PixKeyType`.
+Valida uma chave Pix: um CPF, um CNPJ, um e-mail, um telefone celular brasileiro ou uma chave aleatória EVP, conforme os formatos de chave do DICT.
+
+- **Opções** (`IsValidPixKeyOptions`): `accept` (`PixKeyType[]`, padrão todos) lista os tipos de chave aceitos; `[]` rejeita todos.
+- Mesmas regras de reconhecimento de `getPixKeyInfo`.
```javascript
import { isValidPixKey } from '@brazilian-utils/brazilian-utils';
@@ -290,9 +365,16 @@ isValidPixKey('123.456.789-09', { accept: ['email', 'evp'] }); // false
isValidPixKey('not a key'); // false
```
+Fonte: [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf), [API do DICT](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT.html), [pix-api](https://github.com/bacen/pix-api).
+
### getPixKeyInfo
-Identifica uma chave Pix e a normaliza para a forma canônica que o DICT espera dentro do BR Code: CPF com 11 dígitos, CNPJ com 14 caracteres, e-mail em minúsculas, telefone celular em E.164 (um telefone fixo não é chave Pix) ou UUID em minúsculas (EVP). Um valor de 11 dígitos válido tanto como CPF quanto como celular é lido como CPF, a menos que tenha sido escrito como telefone (prefixo `+55`/`0055` ou DDD entre parênteses). O CPF e o telefone são reconhecidos pela forma como são escritos, não apenas pelos dígitos que carregam, então texto ao redor não é descartado e `'abc123.456.789-09'` não é uma chave CPF. Uma chave de e-mail é trimada e passada para minúsculas, e uma maior que os 77 caracteres que o DICT permite é rejeitada. Um valor cujos dígitos carregam um dígito verificador de CNPJ válido é lido como CNPJ mesmo quando começa com `0055`, já que uma chave de telefone dentro do BR Code sempre carrega o prefixo `+55`. Retorna `null` quando o valor não é uma chave Pix válida. O resultado é tipado como `PixKeyInfo`.
+Identifica uma chave Pix e a normaliza para a forma canônica que o DICT espera dentro de um BR Code. Retorna `null` quando o valor não é uma chave Pix válida.
+
+- Retorna um `PixKeyInfo` com o `type` (`PixKeyType`) e o `value`.
+- O `value` canônico é só dígitos para CPF ou CNPJ (letras maiúsculas), e-mail minúsculo, celular em E.164 ou UUID minúsculo.
+- Um valor de 11 dígitos válido como CPF e celular é lido como CPF, salvo se escrito como telefone (prefixo `+55` ou DDD entre parênteses).
+- Um e-mail com mais de 77 caracteres é rejeitado.
```javascript
import { getPixKeyInfo } from '@brazilian-utils/brazilian-utils';
@@ -307,9 +389,17 @@ getPixKeyInfo('51998259765'); // { type: 'cpf', value: '51998259765' } (também
getPixKeyInfo('+5551998259765'); // { type: 'phone', value: '+5551998259765' }
```
+Fonte: [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf), [API do DICT](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT.html).
+
### isValidPixPayload
-Valida se um payload de BR Code Pix (a string por trás de um QR Code Pix e do "Pix copia e cola") é válido: estrutura TLV bem formada, objetos obrigatórios presentes, um dos templates "Merchant Account Information" carregando o GUI `br.gov.bcb.pix` junto com uma chave ou uma URL, e um CRC-16 que confere. O objeto "Point of Initiation Method" (`01`) é informativo: o Manual do BR Code o marca como opcional e só atribui significado ao valor `"12"` ("só pode ser utilizado uma vez"), então ele pode estar ausente em qualquer um dos formatos e apenas um valor fora de `{"11", "12"}` torna o payload inválido. Quando um payload construído em torno de uma chave traz um valor (`54`), esse valor precisa ser maior que zero, a menos que o payload seja um BR Code de Pix Saque, ou seja, a menos que traga o ISPB do facilitador de serviço de saque no subobjeto 26-03 (`fss`) como prescreve o §2.6 do manual do Pix; rejeitar `"0"`/`"0.00"` sem o `fss` é uma restrição deliberada desta biblioteca, não uma regra do manual. Um `fss` escrito ao lado de uma localização de PSP torna o payload inválido: o §2.7 do Manual de Padrões para Iniciação do Pix mapeia o QR Code dinâmico para exatamente dois subobjetos, `00` (GUI) e `25` (URL), e o `fss` pertence ao template estático do §2.6. A chave em si não é validada contra os formatos do DICT, use `isValidPixKey` para isso. Os Unreserved Templates (IDs 80 a 99) são ignorados: o "QR Code composto" do Pix Automático (Pix recorrente) grava em um deles a localização de recorrência e, quando esse payload também traz uma localização de pagamento em 26-25, como no exemplo composto do manual do Pix, ele é aceito e lido como um payload dinâmico comum, com a localização de recorrência descartada. Só um payload sem nenhum template Pix nos IDs 26 a 51 é considerado inválido.
+Valida um payload de BR Code Pix (a string por trás de um QR Code Pix e do "Pix copia e cola"). A chave em si não é conferida; use `isValidPixKey`.
+
+- A estrutura TLV, o CRC-16 e os objetos obrigatórios (format indicator, category code, moeda, país, nome e cidade do recebedor) são verificados.
+- Um template "Merchant Account Information" (IDs 26 a 51) precisa trazer o GUI `br.gov.bcb.pix` com uma chave (estático) ou a URL do PSP (dinâmico), nunca os dois.
+- Os objetos `01` (Point of Initiation Method) e `62` (Additional Data Field) são opcionais; `01` precisa ser `11` ou `12` quando presente.
+- Um valor (`54`) precisa ser maior que zero, exceto num BR Code de Pix Saque (`fss` de 8 dígitos no subobjeto 26-03).
+- Os Unreserved Templates (IDs 80 a 99) são ignorados.
```javascript
import { isValidPixPayload } from '@brazilian-utils/brazilian-utils';
@@ -322,9 +412,16 @@ isValidPixPayload(
isValidPixPayload('00020126580014br.gov.bcb.pix...'); // false (CRC quebrado)
```
+Fonte: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
### getPixPayloadInfo
-Interpreta um payload de BR Code Pix e retorna seus campos. O payload é validado pelo `isValidPixPayload` primeiro, então uma estrutura malformada, um CRC quebrado ou um objeto obrigatório ausente retornam `null` em vez de um resultado parcial. Um payload estático vem com `key`, um dinâmico com `url`. A chave Pix em si não é validada, já que o manual permite um QR Code estático construído com uma chave que não existe mais no DICT; a titularidade da chave só é resolvida no momento do pagamento. O "Additional Data Field Template" (ID 62) é obrigatório na tabela do BR Code mas opcional na especificação EMV® a que ela se refere, então é aceito quando ausente. Os tamanhos que o manual reserva para o nome do recebedor (25), a cidade do recebedor (15), o `txid` (25) e o campo 26-01 da chave Pix (77) são limites do lado do gerador, aplicados por `generatePixPayload` e não verificados aqui, já que payloads reais os ultrapassam com frequência. O resultado é tipado como `PixPayloadInfo`; `pointOfInitiation` está sempre presente e é tipado como `PixPointOfInitiation`, `"dynamic"` quando o payload traz uma localização de PSP ou quando o objeto "Point of Initiation Method" (`01`) é `"12"`, e `"static"` nos demais casos. As informações da conta do recebedor devem trazer exatamente um entre uma chave e uma `url` (verificada com a mesma regra de localização de PSP do `generatePixPayload`); o próprio `01` é informativo, então pode estar ausente em qualquer um dos formatos e apenas um valor fora de `{"11", "12"}` retorna `null`. Quando um payload construído em torno de uma chave traz um valor, esse valor precisa ser maior que zero, a menos que o payload seja um BR Code de Pix Saque: o §2.6 do manual do Pix coloca o ISPB do facilitador de serviço de saque no subobjeto 26-03 (`fss`), devolvido como `withdrawalFacilitator`, e `54` igual a `"0"` ou `"0.00"` é aceito junto dele. Rejeitar um valor zero sem o `fss` é uma restrição deliberada desta biblioteca, não uma regra do manual. Um `fss` escrito ao lado de uma localização de PSP retorna `null`: o §2.7 do Manual de Padrões para Iniciação do Pix mapeia o QR Code dinâmico para exatamente dois subobjetos, `00` (GUI) e `25` (URL), e o `fss` pertence ao template estático do §2.6. Quando o payload traz uma localização de PSP, o valor e o `txid` são ignorados, como o manual determina. Os Unreserved Templates (IDs 80 a 99) são ignorados: um "QR Code composto" do Pix Automático que também traga uma localização de pagamento em 26-25 é interpretado como um payload dinâmico comum e sua localização de recorrência é descartada, então quem precisa distinguir os dois não pode se apoiar neste parser. Só um payload sem nenhum template Pix nos IDs 26 a 51 retorna `null`.
+Interpreta um payload de BR Code Pix e retorna seus campos. Aceita o que `isValidPixPayload` aceita; para o resto retorna `null`, nunca um resultado parcial.
+
+- Retorna um `PixPayloadInfo`: `merchantName`, `merchantCity`, `pointOfInitiation` e `key` (estático) ou `url` (dinâmico).
+- `amount`, `txid`, `description` e `withdrawalFacilitator` (o `fss` do Pix Saque) só aparecem quando o payload os traz; `txid` fica ausente para o marcador `***`.
+- `pointOfInitiation` (`PixPointOfInitiation`) é `"dynamic"` quando o payload traz uma localização de PSP ou o objeto `01` é `"12"`; senão, `"static"`.
+- Com localização de PSP, `amount` e `txid` são ignorados, como manda o manual.
```javascript
import { getPixPayloadInfo } from '@brazilian-utils/brazilian-utils';
@@ -341,11 +438,18 @@ getPixPayloadInfo(
// }
```
+Fonte: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
### generatePixPayload
-Gera o payload de um BR Code Pix. Exatamente um entre `params.key` e `params.url` deve ser informado (parte de `GeneratePixPayloadParams`); `null` é retornado quando ambos ou nenhum são informados. `url` deve ser uma localização de PSP como o manual do Bacen define: um host com caminho, sem esquema (`pix.example.com/qr/v2/1234`); um payload dinâmico não pode carregar `amount` nem `txid`, que pertencem à localização do PSP. O valor é escrito com as duas casas decimais que o BR Code aceita, então tanto um que arredonda para `0.00` quanto um que não sobrevive a esse round-trip (`0.005`, `123.456`) são rejeitados, em vez de escritos como uma quantia diferente. O BR Code de Pix Saque, que anuncia o `fss` do subobjeto 26-03, é interpretado pelo `getPixPayloadInfo`, mas não é gerado aqui.
+Gera o payload de um BR Code Pix. Exatamente um entre `params.key` e `params.url` deve ser informado; `null` é retornado quando ambos ou nenhum são informados.
-Quando `params.key` é informado, ela é normalizada para a forma canônica do DICT pelo `getPixKeyInfo` e o payload é estático. Quando `params.url` é informado no lugar (a localização do PSP, sem o esquema da URL, ex.: `"pix.example.com/qr/v2/1234"`), o payload é dinâmico conforme o Manual de Padrões para Iniciação do Pix: a URL ocupa o lugar da chave no template "Merchant Account Information" e o objeto "Point of Initiation Method" é definido como dinâmico (`12`); `params.url` pode ter no máximo 77 caracteres. `merchantName`, `merchantCity` e `description` são convertidos para ASCII imprimível (acentos removidos) e truncados ao que o BR Code permite. O `getPixPayloadInfo` já interpreta os dois formatos, então `getPixPayloadInfo(generatePixPayload({ url, ... }))` forma um round-trip.
+- **Parâmetros** (`GeneratePixPayloadParams`): `key` ou `url`, `merchantName`, `merchantCity` e os opcionais `amount`, `txid` e `description`.
+- Com `key` o payload é estático e a chave é normalizada por `getPixKeyInfo`. Com `url` é dinâmico (objeto `01` definido como `12`) e não pode carregar `amount` nem `txid`.
+- `url` é uma localização de PSP: host e caminho, sem esquema (`pix.example.com/qr/v2/1234`), com no máximo 77 caracteres.
+- `amount` recebe duas casas decimais; `0.005`, `123.456` ou um valor que arredonda para `0.00` é rejeitado.
+- `txid` tem de 1 a 25 caracteres de `[A-Za-z0-9]` (padrão `***`).
+- `merchantName`, `merchantCity` e `description` perdem os acentos e são truncados a 25, 15 e o que sobra do template.
```javascript
import { generatePixPayload } from '@brazilian-utils/brazilian-utils';
@@ -368,13 +472,28 @@ generatePixPayload({
generatePixPayload({ merchantName: 'Fulano', merchantCity: 'Brasília' }); // null (nem key nem url)
```
+Fonte: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
## Chave de NF-e
### isValidNfeKey
-Valida se uma chave de acesso de DF-e (Documento Fiscal eletrônico) é válida. Cobre todos os documentos cuja chave de acesso é a mesma string de 44 dígitos: NF-e (modelo 55), NFC-e (65), CT-e (57, o Conhecimento de Transporte Eletrônico instituído pela cláusula primeira do [Ajuste SINIEF 09/07](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2007/AJ_009_07)), MDF-e (58), CT-e OS (67, o Conhecimento de Transporte Eletrônico para Outros Serviços instituído pela cláusula primeira do [Ajuste SINIEF 36/19](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2019/AJ036_19)), GTV-e (64, o CT-e Guia de Transporte de Valores instituído pela cláusula primeira do [Ajuste SINIEF 03/20](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2020/ajuste-sinief-03-20)), BP-e (63), NF3e (66) e NFCom (62). O CF-e-SAT (59) fica de fora: sua "chave de consulta" de 44 posições é composta de outro jeito. Os 44 dígitos podem ser separados nos grupos impressos de 4 por espaço em branco, `.`, `-` ou `/`, inclusive uma sequência deles entre dois grupos, a mesma máscara intercambiável que `isValidCpf` e `isValidCnpj` aceitam; um separador dentro de um grupo de 4, ou qualquer outro caractere, é rejeitado em vez de removido. Os prefixos `NFe`, `CTe`, `MDFe`, `BPe`, `NF3e` e `NFCom` encontrados no atributo `Id` do XML do documento são removidos antes dessa verificação, junto com qualquer espaço em branco entre o prefixo e o primeiro grupo.
+Valida uma chave de acesso de DF-e. Cobre todo DF-e com chave de acesso de 44 dígitos; o CF-e-SAT (59) fica de fora.
-O tipo de emissão (`tpEmis`) é conferido contra os códigos que o MOC daquele modelo atribui, então o conjunto aceito muda com o modelo: de 1 a 7 e 9 para NF-e e NFC-e, `{1, 3, 4, 5, 7, 8}` para o CT-e, `{1, 5, 7, 8}` para o CT-e OS, `{1, 2, 7, 8}` para a GTV-e, `{1, 2, 3}` para o MDF-e e `{1, 2}` para o BP-e, a NF3e e a NFCom. O código 8, a autorização pela SVC-SP, é atribuído somente pelo [MOC do CT-e 4.00](https://dfe-portal.svrs.rs.gov.br/CTE/Documentos), nunca pelo da NF-e; os domínios do [BP-e](https://dfe-portal.svrs.rs.gov.br/BPE/Documentos), da [NF3e](https://dfe-portal.svrs.rs.gov.br/NF3e/Documentos) e da [NFCom](https://dfe-portal.svrs.rs.gov.br/NFCOM/Documentos) vêm dos manuais deles. Para NF-e e NFC-e o código numérico também é conferido contra a regra B03-10 do MOC da NF-e, que proíbe os vinte valores repetidos e sequenciais de `cNF` que ela lista e um `cNF` igual ao número do documento. Já um número de documento todo zerado é recusado em todos os modelos seguindo o leiaute, não por escolha desta biblioteca: o `tiposBasico_v4.00.xsd` do [pacote de schemas da NF-e](https://dfe-portal.svrs.rs.gov.br/NFE/Documentos) tipa o `nNF` como `TNF`, cujo pattern é `[1-9]{1}[0-9]{0,8}`, e o Anexo I de cada um dos outros modelos repete o mesmo regex no seu próprio campo de número.
+- Modelos: NF-e (55), NFC-e (65), CT-e (57), MDF-e (58), CT-e OS (67), GTV-e (64), BP-e (63), NF3e (66) e NFCom (62).
+- Os 44 dígitos podem ser agrupados de 4 em 4 por espaço, `.`, `-` ou `/`. Os prefixos `Id` do XML (`NFe`, `CTe`, `MDFe`, `BPe`, `NF3e`, `NFCom`) são removidos antes.
+- `tpEmis` precisa ser um dos que o MOC do modelo atribui (tabela abaixo).
+- Para NF-e e NFC-e o `cNF` precisa passar na regra B03-10 do MOC (sem valores repetidos ou sequenciais, diferente do número do documento).
+- Um número de documento todo zerado é rejeitado. O dígito verificador é um módulo 11 sobre os 43 primeiros dígitos.
+
+| Modelo | `tpEmis` aceitos |
+| --- | --- |
+| NF-e (55), NFC-e (65) | 1 a 7 e 9 |
+| CT-e (57) | 1, 3, 4, 5, 7, 8 |
+| CT-e OS (67) | 1, 5, 7, 8 |
+| GTV-e (64) | 1, 2, 7, 8 |
+| MDF-e (58) | 1, 2, 3 |
+| BP-e (63), NF3e (66), NFCom (62) | 1, 2 |
```javascript
import { isValidNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -386,13 +505,20 @@ isValidNfeKey('3517 0458 7165 2300 0119 5500 1000 0000 1210 0012 3458'); // true
isValidNfeKey('3517.0458.7165.2300.0119.5500.1000.0000.1210.0012.3458'); // true (qualquer um dos caracteres de máscara)
isValidNfeKey('351 70458716523000119550010000000121000123458'); // false (separador dentro de um grupo de 4)
isValidNfeKey('99170458716523000119550010000000121000123458'); // false (cUF inválido)
+isValidNfeKey('35170458716523000119010010000000121000123450'); // false (modelo inválido)
isValidNfeKey('35170458716523000119550010000000128000123455'); // false (o MOC da NF-e não atribui tpEmis 8)
isValidNfeKey('35170458716523000119550010000000121000000003'); // false (cNF 00000000, regra B03-10)
```
+Fonte: [MOC da NF-e](https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-visao-geral.pdf), [schemas da NF-e](https://dfe-portal.svrs.rs.gov.br/NFE/Documentos) e os MOCs citados em `src/is-valid-nfe-key/is-valid-nfe-key.ts`.
+
### formatNfeKey
-Formata uma chave de acesso de DF-e (Documento Fiscal eletrônico) em grupos de 4 dígitos separados por espaço, a forma em que todo documento auxiliar a imprime: o DANFE da NF-e e da NFC-e, o DACTE do CT-e, do CT-e OS e da GTV-e, o DAMDFE do MDF-e, o DABPE do BP-e, o DANF3E da NF3e e o DANFE-COM da NFCom. Como todo formatador deste pacote, o valor é lido pelos seus dígitos e agrupado até onde eles vão, então uma chave com máscara ou parcial, ainda sendo digitada, é agrupada progressivamente, e qualquer coisa sem dígito (um objeto, `true`, um objeto criado com `Object.create(null)`) devolve `''` em vez de lançar. Use `isValidNfeKey` para verificar uma chave. O `options.pad` (parte de `FormatNfeKeyOptions`) preenche o valor com zeros à esquerda até os 44 dígitos de uma chave de acesso completa (padrão `false`). O parâmetro é tipado como string porque 44 dígitos são mais do que um número JavaScript comporta com exatidão; em tempo de execução um número é lido como a string dos seus dígitos, como em todo formatador deste pacote.
+Formata uma chave de acesso de DF-e (Documento Fiscal eletrônico) em grupos de 4 dígitos separados por espaço. É a forma em que o DANFE, o DACTE, o DAMDFE, o DABPE, o DANF3E e o DANFE-COM a imprimem.
+
+- **Opções** (`FormatNfeKeyOptions`): `pad` preenche o valor com zeros à esquerda até os 44 dígitos de uma chave de acesso completa (padrão `false`).
+- Uma chave com máscara ou parcial é agrupada até onde os dígitos vão.
+- Use `isValidNfeKey` para verificar uma chave.
```javascript
import { formatNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -408,7 +534,9 @@ formatNfeKey('12345', { pad: true });
### parseNfeKey
-Remove a formatação de uma chave de acesso de DF-e, mantém apenas os dígitos e limita o resultado a 44 dígitos. Os prefixos `NFe`, `CTe`, `MDFe`, `BPe`, `NF3e` e `NFCom` que o atributo `Id` do XML do documento coloca antes da chave são retirados primeiro, já que o `NF3e` carrega um dígito próprio; use `isValidNfeKey` para verificar a chave e `getNfeKeyInfo` para ler os campos dela.
+Remove a formatação de uma chave de acesso de DF-e (chave de acesso), mantém apenas os dígitos e limita o resultado a 44 dígitos.
+
+- Os prefixos `Id` do XML (`NFe`, `CTe`, `MDFe`, `BPe`, `NF3e`, `NFCom`) são removidos antes.
```javascript
import { parseNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -422,7 +550,10 @@ parseNfeKey('NFe35170458716523000119550010000000121000123458');
### getNfeKeyInfo
-Interpreta uma chave de acesso de DF-e e retorna seus campos (stateCode, year, month, taxId, model, series, number, emissionType, code, checkDigit). Aceita as mesmas formas de entrada do `isValidNfeKey` e retorna `null` quando a chave não é válida. O resultado é tipado como `NfeKeyInfo`, cujo `model` é um `NfeKeyModel`. A NFCom (`'62'`) e a NF3e (`'66'`) gastam a posição 36 da chave com o `nSiteAutoriz`, o site do autorizador que recebeu o documento, então para esses dois modelos o resultado também traz `authorizationSite` e o `code` tem 7 dígitos em vez de 8.
+Interpreta uma chave de acesso de DF-e e retorna seus campos. Aceita as mesmas formas de entrada de `isValidNfeKey` e retorna `null` quando a chave não é válida.
+
+- Retorna um `NfeKeyInfo`: `stateCode`, `year`, `month`, `taxId`, `model` (`NfeKeyModel`), `series`, `number`, `emissionType`, `code` e `checkDigit`.
+- Para NFCom e NF3e (modelos `'62'` e `'66'`) o resultado também traz `authorizationSite` e o `code` tem 7 dígitos em vez de 8.
```javascript
import { getNfeKeyInfo } from '@brazilian-utils/brazilian-utils';
@@ -442,7 +573,9 @@ getNfeKeyInfo('invalid'); // null
### isValidPhone
-Valida se o número de telefone (celular ou fixo) é válido. Um código de país brasileiro (`+55`, `0055` ou um `55` isolado) é aceito e removido antes da validação, seguindo a regra documentada em `parsePhone`. `options.accept` (tipado como `PhoneType[]`, parte de `IsValidPhoneOptions`) define quais tipos de número são aceitos e tem como padrão `['mobile', 'landline']`; adicione `'service'` para também aceitar os números não geográficos reconhecidos por `isValidServicePhone`, ou informe `[]` para não aceitar nenhum. `options.version` (tipado como `PhoneVersion`, parte do mesmo tipo) é repassado ao `isValidMobilePhone` e escolhe qual regra de numeração celular é aplicada: `1` (padrão) o formato antigo, cujo primeiro dígito do número pode ser 6, 7, 8 ou 9, e `2` o atual, da Resolução Anatel 749/2022, art. 12, I, "a", que aceita 7, 8 ou 9 e rejeita o prefixo `700`. Vale apenas para celulares; números fixos e de serviço não são afetados.
+Valida um número de telefone (celular ou fixo). Um código de país brasileiro (`+55`, `0055` ou um `55` isolado) é aceito e removido antes, como em `parsePhone`.
+
+- **Opções** (`IsValidPhoneOptions`): `accept` (`PhoneType[]`, padrão `['mobile', 'landline']`) define quais tipos de número são aceitos; inclua `'service'` para os números que `isValidServicePhone` reconhece. `version` (`PhoneVersion`, padrão `1`) é repassado a `isValidMobilePhone`.
```javascript
import { isValidPhone } from '@brazilian-utils/brazilian-utils';
@@ -456,9 +589,17 @@ isValidPhone('08001234567', { accept: ['service'] }); // true
isValidPhone('11900000000', { accept: [] }); // false
```
+Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### formatPhone
-Formata número de telefone de acordo com padrões brasileiros. `options.mask` (tipado como `PhoneMask`) aceita `"sn"` (padrão, apenas o número assinante, 9 dígitos, sem DDD), `"nanp"` (DDD + número assinante, `"(00) 00000-0000"` para os 11 dígitos de um celular e `"(00) 0000-0000"` para os 10 dígitos de um fixo, mantendo o agrupamento de 11 dígitos em qualquer outro tamanho), `"e164"` (`"+5511987654321"`), `"international"` (`"+55 11 98765-4321"`, a forma como um número brasileiro é exibido para quem liga do exterior), `"service"` (`"0800 123 4567"` ou `"4004-1234"`, os agrupamentos convencionais para números de serviço) ou `"auto"`. O `"auto"` usa `"international"` quando `value` traz um código de país brasileiro (`+55`, `0055` ou um `55` seguido de 10 ou 11 dígitos), `"service"` quando `value` é um número de serviço e, nos demais casos, decide pela quantidade de dígitos: `"nanp"` quando `value` tem mais dígitos que um número assinante isolado, `"sn"` quando não tem. `"e164"` e `"international"` removem antes o código de país (regra documentada em `parsePhone`) e recaem para a apresentação `"service"` no caso de um número de serviço, já que esses não têm forma E.164. Se `value` incluir o DDD, informe `{ mask: 'auto' }` (ou `'nanp'`) explicitamente, já que a máscara padrão `"sn"` assume que não há DDD e trunca silenciosamente um DDD presente. Uma `mask` fora da união recai para o padrão `"sn"` em vez de lançar erro.
+Formata um número de telefone de acordo com os padrões brasileiros. Se `value` incluir o DDD, informe `{ mask: 'auto' }` ou `'nanp'`: a máscara padrão `"sn"` assume que não há DDD e o trunca.
+
+- **Opções** (`FormatPhoneOptions`): `mask` (`PhoneMask`, padrão `"sn"`) escolhe um dos padrões abaixo. Uma `mask` desconhecida recai para `"sn"`.
+- `"sn"`: apenas o número assinante, 9 dígitos. `"nanp"`: DDD mais número assinante, 11 dígitos para celular e 10 para fixo; outros tamanhos mantêm o agrupamento de 11 dígitos.
+- `"e164"` e `"international"` removem antes o código de país, como `parsePhone`, e recaem para `"service"` para um número de serviço.
+- `"service"`: os Códigos Não Geográficos (`0800 123 4567`) e os números abreviados `300X`/`400X` (`4004-1234`).
+- `"auto"`: `"service"` para um número de serviço, `"international"` quando `value` traz código de país, senão `"nanp"` para mais de 9 dígitos, ou `"sn"`.
```javascript
import { formatPhone } from '@brazilian-utils/brazilian-utils';
@@ -473,12 +614,17 @@ formatPhone('+5511987654321', { mask: 'international' }); // +55 11 98765-4321
formatPhone('08001234567', { mask: 'service' }); // 0800 123 4567
formatPhone('40041234', { mask: 'service' }); // 4004-1234
formatPhone('+5511987654321', { mask: 'auto' }); // +55 11 98765-4321 ("auto" detecta o prefixo +55 e escolhe "international")
+formatPhone('5508001234567', { mask: 'auto' }); // 0800 123 4567 ("auto" lê o número 0800, não um +55 08)
formatPhone('11900000000'); // 11900-0000 (CUIDADO: a máscara padrão "sn" trunca um número com DDD)
```
+Fonte: [ITU-T E.164](https://www.itu.int/rec/T-REC-E.164), [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### parsePhone
-Remove a formatação do telefone, mantém apenas os dígitos e limita o resultado a 11 dígitos. Um código de país brasileiro é removido antes, mas somente quando os dígitos restantes tiverem exatamente 10 ou 11 dígitos, ou seja, um número nacional plausível. A regra é baseada no tamanho, não no sinal, então um número da área 55 não é confundido com o código de país.
+Remove a formatação do telefone, mantém apenas os dígitos e limita o resultado a 11 dígitos.
+
+- Um código de país brasileiro (`+55`, `0055` ou um `55` isolado) é removido antes, mas só quando sobram 10 ou 11 dígitos (DDD mais número assinante), então o DDD 55 não é confundido com ele.
```javascript
import { parsePhone } from '@brazilian-utils/brazilian-utils';
@@ -491,7 +637,9 @@ parsePhone('55987654321'); // 55987654321 (DDD 55, não confundido com o código
### generatePhone
-Gera um telefone brasileiro aleatório. Aceita `'mobile'`, `'landline'` ou `'service'` (tipado como `GeneratePhoneType`); um número de serviço não tem DDD. Se omitido, gera aleatoriamente um celular ou um fixo, nunca um número de serviço. Um celular gerado sempre começa com 9, então passa nas duas regras de numeração do `isValidMobilePhone`.
+Gera um telefone brasileiro aleatório. Aceita `'mobile'`, `'landline'` ou `'service'` (`GeneratePhoneType`); sem o tipo, gera um celular ou um fixo ao acaso, nunca um número de serviço.
+
+- Um celular começa com 9 depois do DDD (válido nas duas versões de `isValidMobilePhone`); um fixo tem 8 dígitos depois do DDD, começando com 2 a 6; um número de serviço não tem DDD.
```javascript
import { generatePhone } from '@brazilian-utils/brazilian-utils';
@@ -504,7 +652,9 @@ generatePhone('service'); // '08001234567' ou '40041234'
### isValidMobilePhone
-Valida se o número de telefone celular é válido. `options.version` (tipado como `PhoneVersion`) controla qual regra de numeração celular é aplicada: `1` (padrão) é o formato anterior à Resolução Anatel 749/2022, mantido por compatibilidade com a 2.3.0, cujo primeiro dígito do número (após o DDD) pode ser 6, 7, 8 ou 9; `2` aplica o art. 12, I, "a" da resolução, que coloca 7, 8 e 9 no Serviço Móvel Pessoal (SMP), então um 6 inicial é Reserva Técnica e é rejeitado. A versão `2` também exclui o prefixo `700`, que o art. 12, II reserva ao Serviço Móvel Global por Satélite e não ao SMP, então `isValidMobilePhone('11700123456', { version: 2 })` é `false`; a versão `1` não o exclui e o aceita.
+Valida um número de telefone celular. Um código de país brasileiro (`+55`, `0055` ou um `55` isolado) é aceito e removido antes, como em `parsePhone`.
+
+- **Opções** (`IsValidMobilePhoneOptions`): `version` (`PhoneVersion`, padrão `1`) escolhe a regra de numeração: `1` aceita 6, 7, 8 ou 9 como primeiro dígito; `2` segue a Resolução Anatel 749/2022, aceita só 7, 8 ou 9 e rejeita a série `700`.
```javascript
import { isValidMobilePhone } from '@brazilian-utils/brazilian-utils';
@@ -516,19 +666,26 @@ isValidMobilePhone('11612345678', { version: 2 }); // false (6 é Reserva Técni
isValidMobilePhone('11700123456', { version: 2 }); // false (a série 700 é de satélite)
```
+Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### isValidLandlinePhone
-Valida se o número de telefone fixo é válido.
+Valida um número de telefone fixo. Um código de país brasileiro (`+55`, `0055` ou um `55` isolado) é aceito e removido antes, como em `parsePhone`.
```javascript
import { isValidLandlinePhone } from '@brazilian-utils/brazilian-utils';
isValidLandlinePhone('1130000000'); // true
+isValidLandlinePhone('+55 11 3000-0000'); // true (código de país aceito)
```
### isValidServicePhone
-Valida se um número de telefone é um número de serviço brasileiro válido, discado sem DDD: os Códigos Não Geográficos `0300`, `0303`, `0500`, `0800` e `0900` (11 dígitos no total, então a forma curta e extinta de `0800` + 6 dígitos é rejeitada), os números abreviados `300X`/`400X` (8 dígitos), e os códigos de 3 dígitos dos Códigos de Acesso a Serviços de Utilidade Pública designados pela Anatel (ex.: `190`, `192`), cuja tabela consolidada é o Anexo do [Ato Anatel nº 43.151/2004](https://informacoes.anatel.gov.br/legislacao/atos-de-numeracao/2004/1648-ato-43151). O `112` e o `911` são rejeitados: a Anatel não designa nenhum dos dois, e o `911` sequer está dentro da faixa `1N₂N₁` que o art. 13 da [Resolução nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749) destina aos serviços de utilidade pública, então o encaminhamento deles nos aparelhos é uma convenção GSM, não uma designação de numeração. Apenas a estrutura é verificada: o número não precisa estar atribuído a ninguém, e a regra do `0500` que codifica o valor da doação nos dois últimos dígitos não é aplicada. A Anatel retirou os códigos de 4 dígitos em vez de alocá-los (o art. 43 I da [Resolução nº 86/1998](https://informacoes.anatel.gov.br/legislacao/resolucoes/1998/336-resolucao-86) e o art. 2º II do Ato acima mandaram liberá-los), então apenas as raízes convencionais `300X` e `400X` são reconhecidas: outros prefixos de "Número Único" usados no mercado, como `4020` e `4062`, estão fora de escopo e são rejeitados.
+Valida um número de serviço brasileiro, discado sem DDD. Apenas a estrutura é verificada: o número não precisa estar atribuído a ninguém.
+
+- Os Códigos Não Geográficos `0300`, `0303`, `0500`, `0800` e `0900` seguidos de 7 dígitos (11 no total).
+- Os números abreviados `300X`/`400X`, com 8 dígitos. Outros prefixos de operadora, como `4020` e `4062`, são rejeitados.
+- Os códigos de utilidade pública de 3 dígitos designados pela Anatel (ex.: `190`, `192`). O `112` e o `911` não estão entre eles e são rejeitados.
```javascript
import { isValidServicePhone } from '@brazilian-utils/brazilian-utils';
@@ -539,11 +696,14 @@ isValidServicePhone('190'); // true
isValidServicePhone('11987654321'); // false (número geográfico)
```
+Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Ato Anatel nº 43.151/2004](https://informacoes.anatel.gov.br/legislacao/atos-de-numeracao/2004/1648-ato-43151), [Resolução nº 86/1998](https://informacoes.anatel.gov.br/legislacao/resolucoes/1998/336-resolucao-86).
+
### getAreaCodeInfo
-Retorna o estado (e a região) a que um DDD brasileiro pertence, dentre os 67 DDDs em uso no Plano Geral de Numeração da Anatel. Aceita string ou número inteiro não negativo, removendo caracteres não numéricos antes de comparar. Exporta o tipo `AreaCodeInfo`.
+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.
-`stateCode` é sempre um único estado: a sede do DDD, o estado da cidade em torno da qual o código foi alocado, que não é necessariamente o estado que concentra a maioria dos seus municípios. Quatro DDDs cruzam a divisa de um estado, e para esses o `stateCodes` lista também os demais. O DDD 61 é o mais amplo deles: atende o Distrito Federal e os doze municípios goianos do Entorno do Distrito Federal (Águas Lindas de Goiás, Cabeceiras, Cidade Ocidental, Cristalina, Formosa, Luziânia, Novo Gama, Padre Bernardo, Planaltina, Santo Antônio do Descoberto, Valparaíso de Goiás e Vila Boa), então seu `stateCode` é `'DF'` mesmo o Distrito Federal tendo apenas um dos seus treze municípios, Brasília. Os outros três são o 42, compartilhado entre o Paraná e Porto União (SC), o 47, entre Santa Catarina e Rio Negro (PR), e o 49, entre Santa Catarina e Barracão (PR), e neles a sede realmente concentra todos os municípios menos o citado.
+- 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.
```javascript
import { getAreaCodeInfo } from '@brazilian-utils/brazilian-utils';
@@ -562,11 +722,14 @@ getAreaCodeInfo(-11); // null
getAreaCodeInfo(1.1); // null
```
+Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Códigos Nacionais da Anatel](https://www.gov.br/anatel/pt-br/regulado/numeracao/codigos-nacionais).
+
### getAreaCodesByState
-Retorna todos os DDDs (códigos de área) que atendem um determinado estado brasileiro, dentro do Plano Geral de Numeração da Anatel. A comparação não diferencia maiúsculas de minúsculas e o resultado vem ordenado de forma crescente.
+Retorna todos os DDDs (códigos de área) que atendem um estado brasileiro, dentro do Plano Geral de Numeração da Anatel. A comparação não diferencia maiúsculas de minúsculas e o resultado vem em ordem crescente.
-Um DDD que cruza a divisa de um estado aparece em todos os estados que atende, então o DDD 61 volta tanto para `'DF'` quanto para `'GO'`: ele atende o Distrito Federal e os doze municípios goianos do Entorno do Distrito Federal. Os outros três são o 42, compartilhado entre o Paraná e Porto União (SC), o 47, entre Santa Catarina e Rio Negro (PR), e o 49, entre Santa Catarina e Barracão (PR).
+- Retorna `[]` quando `stateCode` não é um estado brasileiro.
+- Um DDD de divisa (os mesmos quatro de `getAreaCodeInfo`) é listado em cada estado que atende.
```javascript
import { getAreaCodesByState } from '@brazilian-utils/brazilian-utils';
@@ -579,11 +742,13 @@ getAreaCodesByState('SC'); // [42, 47, 48, 49]
getAreaCodesByState('XX'); // []
```
+Fonte: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Códigos Nacionais da Anatel](https://www.gov.br/anatel/pt-br/regulado/numeracao/codigos-nacionais).
+
## Placa de veículo
### isValidLicensePlate
-Valida se a placa de carro ou moto é válida. Suporta o formato antigo brasileiro (ABC-1234) e o formato Mercosul (ABC1D23), a sequência única que a Resolução CONTRAN nº 969/2022 define para todo veículo, motos incluídas.
+Valida uma placa de veículo. Aceita o formato antigo brasileiro (`ABC-1234`) e o formato Mercosul (`ABC1D23`), com ou sem hífen ou espaço, em maiúsculas ou minúsculas.
```javascript
import { isValidLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -596,9 +761,13 @@ isValidLicensePlate('ABC12D3'); // false (não é uma sequência Mercosul)
isValidLicensePlate('ABC1234EXTRA'); // false (caracteres em excesso)
```
+Fonte: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf), [Anexos](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022anexos.pdf).
+
### formatLicensePlate
-Formata uma placa. Placas antigas brasileiras (`LLLNNNN`) são retornadas com hífen e placas Mercosul (`LLLNLNN`) permanecem normalizadas. Valores parciais são formatados até onde os caracteres informados alcançarem, então também pode ser usada como máscara de digitação, e um valor que não pode iniciar uma placa válida retorna `''`.
+Formata uma placa. Placas antigas brasileiras (`LLLNNNN`) recebem hífen; placas Mercosul (`LLLNLNN`) são retornadas sem separador.
+
+- Retorna `''` quando o valor não pode iniciar uma placa válida.
```javascript
import { formatLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -619,7 +788,9 @@ parseLicensePlate('abc-1234'); // 'ABC1234'
### generateLicensePlate
-Gera uma placa aleatória no formato escolhido. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera uma placa válida aleatória no formato escolhido.
+
+- `format` (`GenerateLicensePlateFormat`): `'LLLNLNN'` (Mercosul, o padrão) ou `'LLLNNNN'` (o formato antigo brasileiro). Qualquer outro valor cai no padrão.
```javascript
import { generateLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -629,11 +800,14 @@ generateLicensePlate('LLLNNNN'); // 'ABC1234'
generateLicensePlate('LLLNNLN'); // 'ABC1D23' (um formato fora dos dois em circulação cai no padrão)
```
-Um `format` fora dos dois literais suportados recai no padrão Mercosul, como todo gerador deste pacote faz com uma opção que não conhece, então o resultado é sempre uma placa que `isValidLicensePlate` aceita. Essa sequência padrão é `LLLNLNN`, da Resolução CONTRAN nº 969/2022, Anexo I item 1.2, a única sequência que a resolução define para todo veículo, motocicletas incluídas. (A versão 2.3.0 usava uma string desconhecida literalmente, então `generateLicensePlate('LLLNNLN')` produzia a sequência de motocicleta que foi retirada e `generateLicensePlate('bogus')`, cinco dígitos; nenhuma das duas é uma placa.)
+Fonte: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf).
### getFormatLicensePlate
-Detecta o formato normalizado de uma placa.
+Detecta o formato normalizado de uma placa: `'LLLNNNN'` para o formato antigo brasileiro, `'LLLNLNN'` para o Mercosul.
+
+- Retorna `null` quando o valor, sem os separadores, não tem 7 letras e dígitos em um dos dois formatos.
+- Exporta o tipo `LicensePlateFormat`, que `generateLicensePlate` reexporta como `GenerateLicensePlateFormat`.
```javascript
import { getFormatLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -645,11 +819,11 @@ getFormatLicensePlate('INVALID'); // null
getFormatLicensePlate('ABC1234EXTRA'); // null (caracteres em excesso)
```
-`getFormatLicensePlate` exporta o tipo `LicensePlateFormat` (`"LLLNNNN" | "LLLNLNN"`); `generateLicensePlate` reexporta como `GenerateLicensePlateFormat`.
-
### convertLicensePlateToMercosul
-Converte uma placa brasileira no formato antigo (`LLLNNNN`) para o formato Mercosul (`LLLNLNN`), seguindo a tabela oficial de conversão: o dígito na 5ª posição vira uma letra (`0` a `9` mapeados para `A` a `J`). Retorna `""` quando o valor não é uma placa válida no formato antigo.
+Converte uma placa brasileira no formato antigo (`LLLNNNN`) para o formato Mercosul (`LLLNLNN`). O 5º dígito vira uma letra, `0` a `9` mapeados para `A` a `J`.
+
+- Retorna `""` quando o valor não é uma placa válida no formato antigo.
```javascript
import { convertLicensePlateToMercosul } from '@brazilian-utils/brazilian-utils';
@@ -659,11 +833,15 @@ convertLicensePlateToMercosul('abc-1234'); // 'ABC1C34'
convertLicensePlateToMercosul('ABC1D23'); // '' (já está no formato Mercosul)
```
+Fonte: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf), [Anexo II](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022anexos.pdf).
+
## RENAVAM
### isValidRenavam
-Valida se o RENAVAM (Registro Nacional de Veículos Automotores) é válido. Suporta tanto o formato antigo (9 dígitos) quanto o novo formato (11 dígitos). Espaços, pontos e hífens ao redor/entre os dígitos são ignorados, mas qualquer outro caractere, uma letra em especial, invalida o valor. Um registro com todos os dígitos iguais também é rejeitado.
+Valida um RENAVAM (Registro Nacional de Veículos Automotores). Aceita o formato antigo (9 dígitos) e o formato novo (11 dígitos).
+
+- Espaços, pontos e hífens são ignorados; qualquer outro caractere invalida o valor.
```javascript
import { isValidRenavam } from '@brazilian-utils/brazilian-utils';
@@ -678,7 +856,7 @@ isValidRenavam('ab00639884962'); // false (letras são rejeitadas)
### generateRenavam
-Gera um RENAVAM válido aleatório: o formato de 11 dígitos, dez dígitos de base mais o dígito verificador. Uma base com todos os dígitos iguais é sorteada de novo, já que `isValidRenavam` rejeita essas. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um RENAVAM válido aleatório na forma de 11 dígitos: dez dígitos de base mais o dígito verificador.
```javascript
import { generateRenavam } from '@brazilian-utils/brazilian-utils';
@@ -690,17 +868,22 @@ generateRenavam(); // '12345678900'
### isValidPis
-Valida se o PIS é válido. Aceita os caracteres de máscara usuais (`.`, `-`, `/`, `(`, `)`, `,`, `*`) e espaços em branco.
+Valida um PIS. Aceita o valor com ou sem máscara.
+
+- Um valor com todos os dígitos iguais é rejeitado.
```javascript
import { isValidPis } from '@brazilian-utils/brazilian-utils';
+isValidPis('12056412847'); // true
isValidPis('12056412547'); // false
```
### formatPis
-Formata número de PIS. `options.pad` (parte de `FormatPisOptions`) completa o valor com zeros à esquerda até os 11 dígitos antes de aplicar a máscara (padrão `false`).
+Formata um PIS.
+
+- **Opções** (`FormatPisOptions`): `pad` completa o valor com zeros à esquerda até 11 dígitos antes de aplicar a máscara (padrão `false`).
```javascript
import { formatPis } from '@brazilian-utils/brazilian-utils';
@@ -721,7 +904,7 @@ parsePis('123.45678.90-1'); // 12345678901
### generatePis
-Gera um PIS válido aleatório. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um PIS válido aleatório.
```javascript
import { generatePis } from '@brazilian-utils/brazilian-utils';
@@ -733,7 +916,10 @@ generatePis(); // '91077906857'
### isValidProcessoJuridico
-Valida o número do processo jurídico de acordo com definição do [CNJ](https://atos.cnj.jus.br/atos/detalhar/119): o layout `NNNNNNN-DD.AAAA.J.TR.OOOO`, os dígitos verificadores `DD` e o par `J`/`TR`, que precisa identificar um órgão e um tribunal existentes nas listas fechadas definidas pela Resolução CNJ nº 65/2008, de modo que um número com dígito verificador correto mas com um tribunal inexistente é rejeitado. As listas fechadas vêm do art. 1º, § 4º e § 5º da resolução, o § 5º, III na redação que a Resolução CNJ nº 477/2022 lhe deu para acomodar o TRF da 6ª Região. A unidade de origem (`OOOO`) é lida apenas como quatro dígitos, já que o art. 1º, § 6º deixa a codificação dela a cargo de cada tribunal e não publica lista central. Os separadores da máscara do CNJ (espaços, `.` e `-`) são aceitos entre os campos, e espaços em branco ao redor do valor são ignorados, mas qualquer outro caractere, uma letra em especial, invalida o valor.
+Valida um número de processo jurídico, conforme a Resolução CNJ nº 65/2008. Três coisas são verificadas: o layout `NNNNNNN-DD.AAAA.J.TR.OOOO`, os dígitos verificadores `DD` (ISO 7064 MOD 97-10) e o par `J`/`TR`.
+
+- `J` e `TR` precisam nomear um órgão e um tribunal que existem.
+- A unidade de origem (`OOOO`) é verificada apenas como quatro dígitos.
```javascript
import { isValidProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -745,9 +931,13 @@ isValidProcessoJuridico('0000100-23.2008.8.28.0000'); // false (não existe 28º
isValidProcessoJuridico('ab00020802520125150049'); // false (letras são rejeitadas)
```
+Fonte: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
### formatProcessoJuridico
-Formata um número no formato definido pelo [CNJ](https://atos.cnj.jus.br/atos/detalhar/119) (máscara `NNNNNNN-DD.AAAA.J.TR.OOOO`). `options.pad` (parte de `FormatProcessoJuridicoOptions`) completa o valor com zeros à esquerda até os 20 dígitos antes de aplicar a máscara (padrão `false`).
+Formata um número de processo jurídico na máscara do CNJ `NNNNNNN-DD.AAAA.J.TR.OOOO`.
+
+- **Opções** (`FormatProcessoJuridicoOptions`): `pad` completa o valor com zeros à esquerda até 20 dígitos antes de aplicar a máscara (padrão `false`).
```javascript
import { formatProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -756,9 +946,11 @@ formatProcessoJuridico('00020802520125150049'); // 0002080-25.2012.5.15.0049
formatProcessoJuridico('20802520125150049', { pad: true }); // 0002080-25.2012.5.15.0049
```
+Fonte: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
### parseProcessoJuridico
-Remove a formatação do processo jurídico, mantém apenas os dígitos e limita o resultado a 20 dígitos. Tanto a máscara atual do CNJ (`NNNNNNN-DD.AAAA.J.TR.OOOO`) quanto a máscara antiga são aceitas, já que apenas os dígitos são mantidos.
+Remove a formatação do processo jurídico, mantém apenas os dígitos e limita o resultado a 20 dígitos.
```javascript
import { parseProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -768,7 +960,11 @@ parseProcessoJuridico('0002080-25.2012.5.15.0049'); // 00020802520125150049
### generateProcessoJuridico
-Gera um número de processo jurídico válido de acordo com a definição do [CNJ](https://atos.cnj.jus.br/atos/detalhar/119). `year` deve estar entre o ano atual e 9999, `court` entre 1 e 9; valores fora do intervalo retornam `null`. O órgão (`J`) e o tribunal (`TR`) são sorteados das listas fechadas do art. 1º, § 4º e § 5º, então o par sempre nomeia um tribunal que existe: `court` escolhe o órgão e o `TR` é sorteado entre os tribunais que aquele órgão tem. A unidade de origem (`OOOO`) é sorteada livremente, já que a resolução não publica lista central para ela. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um número de processo jurídico válido aleatório no layout da Resolução CNJ nº 65/2008.
+
+- **Opções** (`GenerateProcessoJuridicoParams`): `year` define o campo `AAAA`, um inteiro entre o ano atual e 9999 (padrão: o ano atual); `court` define o órgão `J`, de 1 a 9 (padrão: aleatório).
+- `TR` é sorteado entre os tribunais do órgão escolhido, então o par sempre nomeia um tribunal que existe.
+- Retorna `null` quando `year` ou `court` está fora do intervalo.
```javascript
import { generateProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -779,11 +975,16 @@ generateProcessoJuridico({ year: 10000 }); // null (ano fora do intervalo)
generateProcessoJuridico({ court: 10 }); // null (órgão inexistente)
```
+Fonte: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
## Contas bancárias e bancos
### isValidBankAccount
-Verifica se uma conta bancária brasileira é válida. O `bankCode` precisa estar na lista de participantes do STR publicada pelo Banco Central do Brasil (o mesmo dataset usado por `getBankByCode`), então um código não atribuído como `'999'` é sempre inválido. A partir daí o banco é validado de uma de três formas: pelo algoritmo de dígito verificador publicado, apenas pela estrutura (o banco existe e a agência/conta respeitam a quantidade de dígitos documentada, para bancos que não publicam regra de dígito) ou pela verificação genérica mod10/mod11, que continua sendo o fallback para os demais bancos da lista.
+Valida uma conta bancária brasileira. O `bankCode` precisa ser um participante do STR do Banco Central (a lista que `getBankByCode` usa).
+
+- **Parâmetros** (`IsValidBankAccountParams`, todos strings): `bankCode` (3 dígitos), `agency` (1-5 dígitos), `account` (1-13 dígitos) e `digit` (1-2 caracteres, ou `X` para o Banco do Brasil e `P` para o Bradesco).
+- Um banco da lista é validado de uma de três formas: pelo algoritmo de dígito verificador publicado, apenas pela estrutura ou por um fallback genérico mod10/mod11.
Bancos validados pelo algoritmo de dígito verificador publicado:
@@ -799,7 +1000,7 @@ Bancos validados pelo algoritmo de dígito verificador publicado:
| HSBC / Kirton Bank | `399` | 4 dígitos | 6 dígitos | pesos `8,9,2,3,4,5,6,7,8,9` sobre agência + conta; resto 10 gera `0` |
| Citibank | `745` | 4 dígitos | 10 dígitos | pesos `11..2` sobre a conta; resto 0 ou 1 gera `0` |
-Bancos validados apenas pela estrutura, por não publicarem regra de dígito verificador. A agência (1-5 dígitos), a conta (1-13 dígitos) e um único `digit` numérico já tornam a conta válida:
+Bancos validados apenas pela estrutura (um único `digit` numérico basta):
| Banco | Código | | Banco | Código |
| --- | --- | --- | --- | --- |
@@ -813,9 +1014,7 @@ Bancos validados apenas pela estrutura, por não publicarem regra de dígito ver
| PagBank | `290` | | Sicredi | `748` |
| BMG | `318` | | Sicoob | `756` |
-Quando `digit` tem 2 caracteres, o fallback genérico encadeia mod10 seguido de mod11 sobre a conta, do mesmo jeito que os dígitos de CPF/CNPJ são encadeados.
-
-Fontes: o compêndio "Regras de Validação de dígito verificador de agência e conta corrente", conferido contra `banktools-br` (Ruby), `luizalabs/heimdall` (Python) e `Xerpa/bran_checker` (Elixir). Cada algoritmo publicado aqui tem pelo menos duas fontes independentes concordantes.
+- Todo outro banco da lista usa o fallback genérico: `digit` precisa bater com mod10 ou mod11 sobre a conta. Um `digit` de 2 caracteres encadeia mod10 e depois mod11.
```javascript
import { isValidBankAccount } from '@brazilian-utils/brazilian-utils';
@@ -884,9 +1083,13 @@ isValidBankAccount({
}); // true (Banco ABC Brasil, fallback genérico mod10)
```
+Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv), [Regras de Validação de dígito verificador](https://github.com/eduardokum/laravel-boleto/blob/master/manuais/Regras%20Validacao%20Conta%20Corrente%20VI_EPS.pdf).
+
### getBanks
-Obtém todos os bancos brasileiros com código de compensação (COMPE), publicados pelo Banco Central do Brasil na [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Cada banco (tipado como `Bank`) tem um `code` (COMPE, 3 dígitos), um `ispb` (Identificador do Sistema de Pagamentos Brasileiro, 8 dígitos) e um `name`. Cada chamada retorna um novo array com novos objetos, então alterar o resultado nunca afeta chamadas seguintes.
+Obtém todos os bancos brasileiros com código de compensação (COMPE), a partir da lista de participantes do STR do Banco Central do Brasil.
+
+- Cada banco (`Bank`) tem um `code` (COMPE, 3 dígitos), um `ispb` (8 dígitos) e um `name`.
```javascript
import { getBanks } from '@brazilian-utils/brazilian-utils';
@@ -900,9 +1103,13 @@ getBanks();
// ]
```
+Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv).
+
### getBankByCode
-Busca um banco brasileiro pelo seu código de compensação (COMPE), publicado pelo Banco Central do Brasil na [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Aceita tanto `string` quanto `number`, com ou sem zeros à esquerda. Retorna uma nova cópia (tipada como `Bank`) do banco correspondente, ou `null` quando nenhum banco tem esse código.
+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`.
+
+- Retorna o `Bank` correspondente, ou `null` quando nenhum banco tem esse código.
```javascript
import { getBankByCode } from '@brazilian-utils/brazilian-utils';
@@ -912,9 +1119,13 @@ getBankByCode(1); // { code: '001', ispb: '00000000', name: 'Banco do Brasil S.A
getBankByCode('999'); // null
```
+Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv).
+
### getBankByIspb
-Busca um banco brasileiro pelo seu ISPB (Identificador do Sistema de Pagamentos Brasileiro), o código de 8 dígitos publicado pelo Banco Central do Brasil na [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Todo participante do SPB tem um ISPB, mas este conjunto de dados só traz as instituições que também têm código COMPE, então um ISPB cuja instituição não tem código COMPE próprio retorna `null`. Aceita tanto `string` quanto `number`, com ou sem zeros à esquerda, então `getBankByIspb(0)` encontra o mesmo banco que `getBankByIspb('00000000')`. O conjunto de dados é gerado a partir desse CSV, recorrendo à [BrasilAPI](https://brasilapi.com.br/api/banks/v1) quando a requisição ao Bacen falha. Retorna uma nova cópia (tipada como `Bank`) do banco correspondente, ou `null` quando nenhum banco tem esse ISPB.
+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.
+
+- 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.
```javascript
import { getBankByIspb } from '@brazilian-utils/brazilian-utils';
@@ -924,11 +1135,17 @@ getBankByIspb('60701190'); // { code: '341', ispb: '60701190', name: 'ITAÚ UNIB
getBankByIspb('99999999'); // null
```
+Fonte: [lista de participantes do STR](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv), [BrasilAPI](https://brasilapi.com.br/api/banks/v1).
+
## IBAN
### isValidIban
-Valida se um IBAN (International Bank Account Number) brasileiro é válido, conforme as [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf) do Bacen (Circular BCB nº 3.625/2013): `BR` + 2 dígitos verificadores ISO 7064 MOD 97-10 + 8 dígitos de ISPB + 5 dígitos de agência + 10 dígitos de conta + 1 letra de tipo de conta (qualquer letra, normalmente `C` para conta corrente ou `P` para conta poupança) + 1 indicador de titularidade (`1` para o primeiro ou único titular até `9` para o nono, depois `A` a `Z` a partir do décimo, então `0` é rejeitado), totalizando 29 caracteres. Somente IBANs brasileiros (código de país `BR`) são reconhecidos; qualquer outro país retorna `false`, já que este pacote não conhece o layout de campos dos outros mais de 90 países da ISO 13616. Não diferencia maiúsculas de minúsculas e aceita as duas formas em que um IBAN é escrito: compacta (`'BR1500000000000010932840814P2'`) ou no formato impresso da ISO 13616, letras e dígitos em grupos de 4 (o último menor), em ambos os casos com espaços em branco opcionais no início e no fim. Os grupos podem ser separados por espaço em branco, `.`, `-` ou `/`, os caracteres de máscara intercambiáveis que `isValidCpf` e `isValidCnpj` aceitam. Apenas um separador fora do limite de um grupo, uma sequência de separadores (a ISO 13616 imprime um único) ou um caractere fora de letras e dígitos faz do valor algo que não é um IBAN, então ele é rejeitado em vez de removido.
+Valida um IBAN (International Bank Account Number) brasileiro. Somente IBANs brasileiros (código de país `BR`) são reconhecidos; qualquer outro país retorna `false`.
+
+- Layout, 29 caracteres: `BR`, 2 dígitos verificadores (ISO 7064 MOD 97-10), ISPB de 8 dígitos, agência de 5, conta de 10, 1 letra de tipo de conta, 1 indicador de titularidade.
+- Tipo de conta: qualquer letra, normalmente `C` ou `P`. Titularidade: `1` a `9`, depois `A` a `Z`.
+- Aceita a forma compacta ou grupos de 4 separados por um espaço, `.`, `-` ou `/`, em maiúsculas ou minúsculas.
```javascript
import { isValidIban } from '@brazilian-utils/brazilian-utils';
@@ -941,9 +1158,13 @@ isValidIban('BR15 000 00000 0000 1093 2840 814P 2'); // false (separador dentro
isValidIban('DE89370400440532013000'); // false (IBAN não brasileiro)
```
+Fonte: [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf), [Circular BCB nº 3.625/2013](https://www.bcb.gov.br/pre/normativos/circ/2013/pdf/circ_3625_v1_O.pdf), [ISO 13616-1:2020](https://www.iso.org/standard/81090.html).
+
### formatIban
-Formata um IBAN no agrupamento impresso da ISO 13616, blocos de 4 caracteres, a apresentação usada em extratos e formulários bancários. Não valida os dígitos verificadores nem o layout dos campos; formata o que for passado, até o limite de 29 caracteres de um IBAN brasileiro, até onde for possível, então a função também pode ser usada como máscara de digitação, e um IBAN de outro país é agrupado do mesmo jeito até esse limite. Use `isValidIban` para verificar a validade. O valor pode ser compacto (`'BR1500000000000010932840814P2'`), já estar no formato impresso da ISO 13616 ou ser um valor parcial ainda sendo digitado (`'BR15'`); como todo formatador deste pacote, ele é lido pelas suas letras e dígitos e agrupado até onde eles vão, qualquer outro caractere (hífen, ponto, espaço a mais) é descartado e as letras viram maiúsculas. Só um valor que não seja string resulta em uma string vazia.
+Formata um IBAN no agrupamento impresso da ISO 13616: blocos de 4 caracteres, a apresentação usada em extratos e formulários bancários. Não valida; para isso, use `isValidIban`.
+
+- Limita o resultado a 29 caracteres, o tamanho de um IBAN brasileiro.
```javascript
import { formatIban } from '@brazilian-utils/brazilian-utils';
@@ -956,7 +1177,7 @@ formatIban('BR15 0000-0000.0000/1093 2840 814P-2'); // 'BR15 0000 0000 0000 1093
### parseIban
-Remove a formatação do IBAN, mantém as letras e os dígitos, coloca o resultado em maiúsculas e o limita aos 29 caracteres de um IBAN brasileiro. Um IBAN carrega letras além de dígitos, então o valor é lido como o `parsePassport` lê um número de passaporte; use `isValidIban` para verificar os dígitos verificadores e `getIbanInfo` para ler os campos.
+Remove a formatação do IBAN, mantém as letras e os dígitos, coloca o resultado em maiúsculas e o limita aos 29 caracteres de um IBAN brasileiro.
```javascript
import { parseIban } from '@brazilian-utils/brazilian-utils';
@@ -967,7 +1188,10 @@ parseIban('br15-0000.0000/0000 1093 2840 814p-2'); // 'BR15000000000000109328408
### getIbanInfo
-Interpreta um IBAN brasileiro em seus campos: 2 (código do país, sempre `BR`) + 2 (dígitos verificadores ISO 7064 MOD 97-10) + 8 (ISPB) + 5 (agência) + 10 (conta) + 1 (tipo de conta, qualquer letra, normalmente `C` para conta corrente ou `P` para conta poupança) + 1 (indicador do titular, `1` a `9` e depois `A` a `Z`). Apenas IBANs brasileiros são suportados: o layout de campos dos demais países da ISO 13616 está fora de escopo, então um IBAN bem formado que não seja `BR` também retorna `null`. Aceita as mesmas formas de entrada que `isValidIban`, compacta ou no formato impresso da ISO 13616 (grupos de 4 separados por um único espaço em branco, `.`, `-` ou `/`), em ambos os casos com espaços em branco opcionais no início e no fim e sem diferenciar maiúsculas de minúsculas, e retorna `null` sempre que `isValidIban` retornaria `false`, inclusive quando o valor carrega um separador fora do limite de um grupo, uma sequência de separadores ou qualquer caractere além de letras e dígitos. O resultado é tipado como `IbanInfo`, cujo `accountType` é uma `string`.
+Interpreta um IBAN brasileiro em seus campos. Retorna um objeto `IbanInfo`, ou `null` sempre que `isValidIban` retornaria `false`.
+
+- Campos, todos strings: `countryCode`, `checkDigits`, `bankIspb`, `branch`, `account`, `accountType` (normalmente `C` ou `P`) e `owner` (`1` a `9`, depois `A` a `Z`).
+- Mesmas regras de entrada de `isValidIban`.
```javascript
import { getIbanInfo } from '@brazilian-utils/brazilian-utils';
@@ -987,11 +1211,17 @@ getIbanInfo('DE89370400440532013000'); // null (IBAN não brasileiro)
getIbanInfo('BR15 000 00000 0000 1093 2840 814P 2'); // null (separador dentro de um grupo)
```
+Fonte: [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf), [Circular BCB nº 3.625/2013](https://www.bcb.gov.br/pre/normativos/circ/2013/pdf/circ_3625_v1_O.pdf), [ISO 13616-1:2020](https://www.iso.org/standard/81090.html).
+
## Moeda, números e datas por extenso
### formatCurrency
-Formata um número inteiro ou float para uma string no padrão BRL. Um `number` é formatado como está (sinal e decimais preservados). Uma entrada em `string` é lida pela mesma regra do `parseCurrency`, com a diferença de que um valor escrito sem nenhum separador permanece em unidades inteiras: o último `,` ou `.` seguido de 1 ou 2 dígitos (ou de até `precision` dígitos, quando esse valor for maior) é o separador decimal, todo outro `,` ou `.` é separador de milhar, e um `-` escrito antes do primeiro dígito é preservado. Assim `'1.234,56'` vira `1.234,56`, `'-10.5'` vira `-10,50` e `'1234'` vira `1.234,00`. `precision` é limitado ao intervalo `0..20` (o limite do pacote, o que o Node 20 ainda impõe ao `Intl.NumberFormat`), o padrão é 2 e volta a 2 quando não é um número finito. Um valor que não seja um número finito (`NaN`, `Infinity`, `-Infinity`) vira string vazia, e um valor que não pode ser convertido em número (um symbol, um objeto simples, um objeto sem protótipo) também; `null`, arrays e booleanos passam por `Number()` como no 2.3.0. `options.symbol` prefixa o resultado com o símbolo monetário `R$` (padrão `false`). As opções são tipadas como `FormatCurrencyOptions`.
+Formata um número ou uma string numérica no padrão BRL (`1.234,56`). Um `number` é formatado como está, com sinal e decimais preservados.
+
+- **Opções** (`FormatCurrencyOptions`): `symbol` (padrão `false`) prefixa o resultado com `R$`; `precision` (padrão 2) define as casas decimais, limitada de 0 a 20.
+- Uma `string` é lida como `parseCurrency` a lê, com uma diferença: um valor sem nenhum separador permanece em unidades inteiras, então `'1234'` vira `1.234,00`.
+- Retorna `''` para um valor não finito ou que não pode ser convertido em número.
```javascript
import { formatCurrency } from '@brazilian-utils/brazilian-utils';
@@ -1009,7 +1239,11 @@ formatCurrency(Number.NaN); // "" (números não finitos viram string vazia)
### parseCurrency
-Transforma uma string para o formato de inteiro ou float. O último `,` ou `.` seguido de 1 ou 2 dígitos (ou de até `precision` dígitos, quando esse valor for maior) é o separador decimal; todo outro `,` ou `.` é separador de milhar. Assim `'R$ 1.234,56'` vira `1234.56`, `'R$ 1.234'` vira `1234`, `'1,5'` vira `1.5` e `'12.34'` vira `12.34`. Um valor escrito sem nenhum separador mantém a convenção de centavos e é dividido por `10 ** precision`, então `'1234'` vira `12.34`. Um `-` escrito antes do primeiro dígito é preservado, então `'-R$ 1,00'` vira `-1`. `precision` (padrão 2, limitado a `0..20`, e voltando a 2 quando não é um número finito) controla quantos dígitos são tratados como subunidades monetárias. As opções são tipadas como `ParseCurrencyOptions`.
+Converte uma string de moeda no padrão BRL em número.
+
+- **Opções** (`ParseCurrencyOptions`): `precision` (padrão 2) é a quantidade de dígitos lidos como subunidades monetárias, limitada de 0 a 20.
+- O último `,` ou `.` seguido de 1 a 2 dígitos (até `precision`, quando maior) é o separador decimal; todo outro `,` ou `.` é separador de milhar.
+- Um valor sem nenhum separador é lido como centavos e dividido por `10 ** precision`.
```javascript
import { parseCurrency } from '@brazilian-utils/brazilian-utils';
@@ -1027,7 +1261,11 @@ parseCurrency(''); // 0
### convertNumberToWords
-Formata um número inteiro por extenso em português do Brasil, ex.: `1235` vira `"mil duzentos e trinta e cinco"`. Só são suportados inteiros de `-999999999999999` a `999999999999999` (999 trilhões em valor absoluto); fora desse intervalo, `NaN` ou um valor não finito retornam `""`. Um `value` não inteiro é truncado em direção a zero antes da conversão. `options.gender` (parte de `ConvertNumberToWordsOptions`) concorda "um/dois" e a centena ("duzentos/duzentas" etc.) com o substantivo que o número qualifica, com padrão `"masculine"`. Um valor inválido de `gender` é ignorado e o padrão é usado. O resultado sai sempre em minúsculas; aplique qualquer outra caixa por conta própria.
+Escreve um número inteiro por extenso em português do Brasil: `1235` vira `"mil duzentos e trinta e cinco"`.
+
+- **Opções** (`ConvertNumberToWordsOptions`): `gender` (padrão `"masculine"`) concorda "um/dois" e a centena ("duzentos/duzentas") com o substantivo que o número qualifica.
+- Aceita inteiros de `-999999999999999` a `999999999999999` (999 trilhões). Um valor não inteiro é truncado em direção a zero.
+- Retorna `""` para um valor fora desse intervalo ou não finito.
```javascript
import { convertNumberToWords } from '@brazilian-utils/brazilian-utils';
@@ -1043,7 +1281,10 @@ convertNumberToWords(NaN); // ""
### convertCurrencyToWords
-Formata um valor monetário em Reais por extenso, no estilo usado para escrever o valor à mão em cheques e contratos, ex.: `1523.45` vira `"mil quinhentos e vinte e três reais e quarenta e cinco centavos"`. O `value` é truncado (não arredondado) para 2 casas decimais. O substantivo no singular é usado para exatamente 1 ("um real", "um centavo") e "de" é inserido antes de "reais" quando o valor é um milhão, bilhão ou trilhão de reais redondo. Um valor que trunca para nada vira `"zero reais"`, sem o prefixo "menos"; qualquer outro valor negativo recebe o prefixo "menos", e uma entrada inválida retorna `""`. Acima de `Number.MAX_SAFE_INTEGER / 100` reais (cerca de 90 trilhões) um double não consegue carregar centavos, então o valor é lido como um número inteiro de reais. Não recebe opções: o resultado sai sempre em minúsculas; aplique qualquer outra caixa por conta própria.
+Escreve um valor em reais por extenso, como em cheques e contratos: `1523.45` vira `"mil quinhentos e vinte e três reais e quarenta e cinco centavos"`. Não recebe opções.
+
+- O `value` é truncado (não arredondado) para 2 casas decimais.
+- Retorna `""` para uma entrada inválida ou um valor acima de 999 trilhões de reais.
```javascript
import { convertCurrencyToWords } from '@brazilian-utils/brazilian-utils';
@@ -1059,7 +1300,10 @@ convertCurrencyToWords(-0.001); // "zero reais" (trunca para nada)
### convertDateToWords
-Formata uma data por extenso em português do Brasil, ex.: `"01/01/2024"` vira `"primeiro de janeiro de dois mil e vinte e quatro"`. Aceita um `Date` (lido pela sua data de calendário local, a mesma convenção usada por `isHoliday`) ou uma string no formato `"dd/mm/yyyy"` ou ISO `"yyyy-mm-dd"`. Com o `options.style` padrão `"full"`, o dia 1 é escrito como "primeiro" e os demais dias usam o número cardinal; com `"month"`, só o nome do mês é escrito por extenso e o dia/ano ficam em dígitos (o dia 1 como `"1º"`, ex.: `"2 de março de 2024"`, `"1º de janeiro de 2024"`). Os nomes dos meses ficam em minúsculo. No estilo `"full"` o ano é escrito por extenso sem a vírgula de milhar que `convertNumberToWords`/`convertCurrencyToWords` usam (`1999` vira `"mil novecentos e noventa e nove"`, não `"mil novecentos e noventa e nove"`), do jeito que uma data é lida em voz alta. `options.weekday` (padrão `false`) prefixa o nome do dia da semana em pt-BR minúsculo seguido de vírgula (`"sábado, dois de março de dois mil e vinte e quatro"`), calculado a partir da data de calendário resolvida. Um valor inválido de `style` é ignorado e o padrão é usado. O resultado sai sempre em minúsculas; aplique qualquer outra caixa por conta própria. O dia 29 de fevereiro é aceito nos anos bissextos do calendário gregoriano proléptico (divisíveis por 4, exceto séculos não divisíveis por 400). Retorna `""` para um `Date` inválido, uma string malformada, um dia/mês que não existe ou uma data anterior ao ano 1.
+Escreve uma data por extenso em português do Brasil: `"01/01/2024"` vira `"primeiro de janeiro de dois mil e vinte e quatro"`. Aceita um `Date`, lido pela sua data de calendário local, ou uma string no formato `"dd/mm/yyyy"` ou ISO `"yyyy-mm-dd"`.
+
+- **Opções** (`ConvertDateToWordsOptions`): `style` (padrão `"full"`) escreve dia, mês e ano por extenso; `"month"` escreve só o mês e deixa dia e ano em dígitos, o dia 1 como `"1º"`. `weekday` (padrão `false`) prefixa o nome do dia da semana em minúsculas e uma vírgula.
+- Retorna `""` para um `Date` inválido, uma string malformada, um dia ou mês que não existe ou uma data anterior ao ano 1.
```javascript
import { convertDateToWords } from '@brazilian-utils/brazilian-utils';
@@ -1080,7 +1324,10 @@ convertDateToWords('29/02/1900'); // "" (1900 não é bissexto)
### getStates
-Retorna todos os estados brasileiros, cada um com sigla, nome, código da região, nome da região e código IBGE de 2 dígitos da Unidade da Federação (`cUF`). A lista é ordenada por nome com `localeCompare` no locale "pt-BR", então nomes acentuados caem onde um leitor brasileiro espera: Pará, Paraíba, Paraná e Rio de Janeiro, Rio Grande do Norte, Rio Grande do Sul. Cada chamada retorna um array novo com objetos novos, então alterar o resultado nunca afeta chamadas seguintes. Exporta os tipos `State`, `StateCode` e `StateName`. `State` é uma união discriminada com um membro por estado, então os campos de um estado ficam amarrados entre si: estreitar um `State` pelo `code` também estreita `name`, `regionCode`, `regionName` e `ibgeCode` (`Extract['name']` é `'São Paulo'`), e uma combinação impossível como `{ code: 'SP', name: 'Acre' }` não é um `State`.
+Retorna todos os estados brasileiros, cada um com sigla, nome, código da região, nome da região e código IBGE de 2 dígitos (`cUF`).
+
+- Ordenados por nome no locale "pt-BR".
+- Exporta os tipos `State`, `StateCode` e `StateName`. `State` é uma união discriminada: estreitá-lo pelo `code` também estreita os demais campos.
```javascript
import { getStates } from '@brazilian-utils/brazilian-utils';
@@ -1117,9 +1364,15 @@ getStates();
// ]
```
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
### getStateByIbgeCode
-Retorna o estado brasileiro cujo código IBGE de 2 dígitos ("cUF", Código da Unidade da Federação) corresponde ao valor informado. É o mesmo código de UF de 2 dígitos presente no primeiro campo de toda chave de acesso de DF-e de qualquer um dos modelos que o `isValidNfeKey` cobre: NF-e (55), NFC-e (65), CT-e (57), MDF-e (58), CT-e OS (67), GTV-e (64), BP-e (63), NF3e (66) e NFCom (62). Aceita string ou número inteiro não negativo, removendo caracteres não numéricos antes de comparar. Exporta o tipo `State`.
+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.
+- Retorna `null` quando o código não corresponde a nenhum estado. Exporta o tipo `State`.
```javascript
import { getStateByIbgeCode } from '@brazilian-utils/brazilian-utils';
@@ -1135,9 +1388,14 @@ getStateByIbgeCode(-35); // null
getStateByIbgeCode(3.5); // null
```
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/v1/localidades/estados), [Manual de Orientação do Contribuinte](https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-visao-geral.pdf)
+
### getStateCodeByName
-Retorna a sigla de um estado brasileiro a partir do nome completo. A comparação ignora acentos, maiúsculas/minúsculas e espaços nas pontas, então `'sao paulo'`, `'SÃO PAULO'` e `' São Paulo '` resolvem para `'SP'`. Toda sequência de espaços internos também vira um único espaço, então `'Rio de Janeiro'` resolve para `'RJ'`, enquanto um nome escrito sem o espaço não corresponde a nada (`'saopaulo'` não é `'São Paulo'`). Exporta o tipo `StateCode`.
+Retorna a sigla de um estado brasileiro a partir do nome completo.
+
+- A comparação ignora acentos, não diferencia maiúsculas de minúsculas e remove os espaços nas pontas; espaços internos repetidos viram um só.
+- Retorna `null` quando nenhum estado corresponde. Exporta o tipo `StateCode`.
```javascript
import { getStateCodeByName } from '@brazilian-utils/brazilian-utils';
@@ -1150,7 +1408,10 @@ getStateCodeByName('Neverland'); // null
### getStateNameByCode
-Retorna o nome completo de um estado brasileiro a partir da sigla. A comparação ignora maiúsculas/minúsculas e espaços nas pontas, então `'sp'`, `'SP'` e `' Sp '` resolvem para `'São Paulo'`. Exporta o tipo `StateName`.
+Retorna o nome completo de um estado brasileiro a partir da sigla.
+
+- A comparação não diferencia maiúsculas de minúsculas e remove os espaços nas pontas.
+- Retorna `null` quando nenhum estado corresponde. Exporta o tipo `StateName`.
```javascript
import { getStateNameByCode } from '@brazilian-utils/brazilian-utils';
@@ -1163,7 +1424,10 @@ getStateNameByCode('ZZ'); // null
### getTimezoneByState
-Retorna o nome do fuso horário do banco de dados IANA (tzdata) para um estado brasileiro, escolhido como o fuso da capital do estado. A comparação ignora maiúsculas/minúsculas e espaços nas pontas. Alguns fusos do tzdata cobrem mais de um estado: `America/Sao_Paulo` também cobre DF, GO, MG, ES, RJ, PR, SC e RS além de SP, e `America/Fortaleza` também cobre MA, PI, RN e PB além do CE. Pernambuco resolve para `America/Recife`, não `America/Noronha`: Fernando de Noronha é um distrito arquipélago de PE, não um estado próprio.
+Retorna o nome do fuso horário IANA (zona do tzdata) de um estado brasileiro: o fuso da sua capital.
+
+- A comparação não diferencia maiúsculas de minúsculas e remove os espaços nas pontas.
+- Retorna `null` quando nenhum estado corresponde.
```javascript
import { getTimezoneByState } from '@brazilian-utils/brazilian-utils';
@@ -1175,9 +1439,16 @@ getTimezoneByState('PE'); // 'America/Recife'
getTimezoneByState('ZZ'); // null
```
+Fonte: [IANA Time Zone Database](https://www.iana.org/time-zones)
+
### getMunicipalities
-Retorna os municípios brasileiros publicados pelo IBGE. Retorna todos os municípios se nenhum estado for fornecido, ou os municípios de um estado específico. Cada município é retornado como `{ code, name, stateCode }`, onde `code` é o código IBGE de 7 dígitos do município. Os resultados são ordenados por nome com `localeCompare` no locale "pt-BR". Cada chamada retorna um array novo com objetos novos, então alterar o resultado nunca afeta chamadas seguintes. Um código de estado desconhecido retorna um array vazio em vez de lançar erro. Só um `stateCode` omitido (ou `undefined`) pede a lista completa: `getMunicipalities(null)` e `getMunicipalities('')` retornam `[]`, enquanto os mais permissivos `getCities(null)` e `getCities('')` retornam todas as cidades. O código do estado é comparado exatamente, inclusive na caixa: `getMunicipalities('sp')` retorna `[]` enquanto `getMunicipalities('SP')` retorna os 645 municípios paulistas. `getMunicipalities` e `getCities` são as únicas buscas por estado sensíveis à caixa; `getStateNameByCode`, `getTimezoneByState`, `getAreaCodesByState` e `getMunicipality` ignoram a caixa.
+Retorna os municípios brasileiros publicados pelo IBGE: todos os municípios, ou só os de um estado quando `stateCode` é informado.
+
+- Cada município (`Municipality`) é `{ code, name, stateCode }`, onde `code` é o código IBGE de 7 dígitos. Ordenados por nome no locale "pt-BR".
+- Só um `stateCode` omitido (ou `undefined`) pede a lista completa: `null` e `''` retornam `[]`.
+- `stateCode` diferencia maiúsculas de minúsculas: `'sp'`, como um código desconhecido, retorna `[]`.
+- Embute todos os 5571 municípios. Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle) para carregá-lo sob demanda via `@brazilian-utils/brazilian-utils/get-municipalities`.
```javascript
import { getMunicipalities } from '@brazilian-utils/brazilian-utils';
@@ -1207,11 +1478,14 @@ getMunicipalities('SP');
getMunicipalities('ZZ'); // []
```
-`getMunicipalities` embute todos os 5571 municípios do IBGE e seus códigos, então carrega o mesmo custo de tamanho de pacote que `getCities`. Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle) para saber como carregá-lo sob demanda via `@brazilian-utils/brazilian-utils/get-municipalities` em vez do import da raiz.
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
### getMunicipalityByCode
-Busca um município brasileiro pelo código IBGE de 7 dígitos. Aceita o código como string ou número, removendo qualquer caractere não numérico antes de comparar; um código informado como número precisa ser um inteiro não negativo, então `-3550308` e `355030.8` retornam `null` em vez de serem lidos como `3550308`. Retorna `{ code, name, stateCode }`, um objeto novo, ou `null` quando o código não tem 7 dígitos ou não corresponde a nenhum município conhecido.
+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.
+- 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
import { getMunicipalityByCode } from '@brazilian-utils/brazilian-utils';
@@ -1226,9 +1500,16 @@ getMunicipalityByCode('0000000'); // null (código desconhecido)
getMunicipalityByCode('123'); // null (não tem 7 dígitos)
```
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
### getCities
-Retorna as cidades brasileiras. **Obsoleta:** use `getMunicipalities` no lugar. Retorna todas as cidades se nenhum estado for fornecido, ou cidades de um estado específico. Cada chamada retorna um array novo, então alterar o resultado nunca afeta chamadas seguintes. Um código de estado desconhecido (ou um valor que não seja `StateCode`) retorna um array vazio em vez de lançar erro, exceto quando é um valor falsy: `getCities(null)` e `getCities('')` são lidos como "nenhum estado informado" e retornam todas as cidades, enquanto o mais estrito `getMunicipalities` retorna `[]` para eles. O código do estado é comparado exatamente, inclusive na caixa: `getCities('sp')` retorna `[]` enquanto `getCities('SP')` retorna as 645 cidades paulistas. `getCities` e `getMunicipalities` são as únicas buscas por estado sensíveis à caixa; `getStateNameByCode`, `getTimezoneByState`, `getAreaCodesByState` e `getMunicipality` ignoram a caixa.
+Retorna os nomes das cidades brasileiras: todas as cidades, ou só as de um estado. **Descontinuada:** use `getMunicipalities` no lugar.
+
+- Ordenadas no locale "pt-BR".
+- Qualquer `state` falsy pede a lista completa, enquanto `getMunicipalities` retorna `[]`.
+- `state` diferencia maiúsculas de minúsculas: `'sp'`, como um código desconhecido, retorna `[]`.
+- Embute os 5571 nomes (~154,2 KB minificado, ~49,8 KB com gzip). Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle) para carregá-la sob demanda via `@brazilian-utils/brazilian-utils/get-cities`.
```javascript
import { getCities } from '@brazilian-utils/brazilian-utils';
@@ -1266,11 +1547,16 @@ getCities('SP');
// ]
```
-`getCities` embute os nomes dos 5571 municípios do IBGE (~154,2 KB minificado, ~49,8 KB com gzip) e é uma das poucas exceções pesadas neste pacote, que é tree-shakeable no restante. Veja [Tamanho do bundle](pt-br/getting-started.md#tamanho-do-bundle) para saber como carregá-lo sob demanda via `@brazilian-utils/brazilian-utils/get-cities` em vez do import da raiz.
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
### getMunicipality
-Busca informações de município por código IBGE, ou obtém o código IBGE a partir do nome do município e UF. **Obsoleta:** use `getMunicipalityByCode` no lugar, que é síncrona e offline; casar um município pelo nome fica a cargo da aplicação, sobre `getMunicipalities`. Uma única função cobre as duas direções, dependendo se `options` tem `code` ou `municipalityName`/`uf`. `code` aceita tanto `string` quanto `number` e deve ter exatamente 7 dígitos, caso contrário a função resolve para `null`. Um `code` informado como número precisa ser um inteiro não negativo: sinal e ponto decimal não são dígitos, então `-3550308` e `355030.8` resolvem para `null` em vez de serem lidos como `3550308`. A resolução é totalmente offline, a partir de um dataset do IBGE embutido na biblioteca: nenhuma requisição de rede é feita. A comparação do nome do município ignora acentos e diferenças entre maiúsculas/minúsculas, e toda sequência de espaços vira um único espaço, então `'sao paulo'` corresponde a `'São Paulo'`, enquanto um nome escrito sem o espaço não; a caixa é convertida para maiúsculas, a direção em que o Unicode expande `'ß'` para `'SS'`, então `'Paßos'` corresponde a `'Passos'`. Um município desconhecido, uma UF desconhecida ou uma entrada inválida resolvem para `null`. O par `[name, uf]` é um array novo a cada chamada, então alterar o resultado nunca afeta as buscas seguintes.
+Busca informações de município por código IBGE, ou um código IBGE a partir do nome do município e UF. **Descontinuada:** use `getMunicipalityByCode` no lugar, que é síncrona e offline; casar um município pelo nome fica a cargo da aplicação, sobre `getMunicipalities`.
+
+- Uma única função cobre as duas direções, dependendo se `options` tem `code` ou `municipalityName`/`uf`. A busca é offline: nenhuma requisição de rede é feita.
+- A comparação do nome ignora acentos, não diferencia maiúsculas de minúsculas e reduz espaços repetidos a um só.
+- Resolve para `null` para um município desconhecido, uma UF desconhecida ou uma entrada inválida.
+- `GetMunicipalityOptions`, `GetMunicipalityByCodeOptions` e `GetMunicipalityByNameOptions` são aliases descontinuados dos tipos abaixo.
```javascript
import { getMunicipality } from '@brazilian-utils/brazilian-utils';
@@ -1291,8 +1577,6 @@ await getMunicipality({ code: '123' });
// null (não tem 7 dígitos)
```
-Em TypeScript o tipo de retorno acompanha a direção da busca: uma consulta `{ code }` resolve para `[string, string] | null`, uma consulta `{ municipalityName, uf }` resolve para `string | null`, e uma consulta cuja direção só é conhecida em tempo de execução (uma variável tipada como `GetMunicipalityParams`) resolve para a união das duas. Os nomes da 2.3.0 `GetMunicipalityOptions`, `GetMunicipalityByCodeOptions` e `GetMunicipalityByNameOptions` continuam exportados como aliases deprecados destes.
-
```typescript
import {
getMunicipality,
@@ -1314,22 +1598,19 @@ const lookUp = (options: GetMunicipalityParams) => getMunicipality(options);
// (options: GetMunicipalityParams) => Promise<[string, string] | string | null>
```
+Fonte: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
## Feriados e dias úteis
### getHolidays
-Retorna feriados brasileiros para um determinado ano. Retorna feriados nacionais e opcionalmente feriados estaduais. Cada feriado (tipado como `Holiday`) tem um campo `type` (`HolidayType`: `"national"`, `"state"`, `"optional"` ou `"religious"`). O "Dia da Consciência Negra" (20 de novembro) é feriado nacional a partir de 2024 (Lei nº 14.759/2023). Antes disso, vários estados ainda trazem um feriado estadual próprio na mesma data, com o mesmo nome `"Dia da Consciência Negra"` em MT, RJ, AM e SP, e com `"Dia Estadual da Consciência Negra"` no AP, o nome que a lei daquele estado usa. Datas comemorativas que nenhuma lei transforma em feriado não entram na lista: o "Dia do Rio Grande do Norte" do RN (7 de agosto, Lei RN nº 7.831/2000) é uma delas, e o "Dia dos Evangélicos" de RO (18 de junho) também não entra, porque o STF derrubou a lei que o criou na ADI 3940. Os resultados são memoizados por `year`/`stateCode`, mas cada chamada ainda retorna uma cópia nova. Um `stateCode` desconhecido/inválido é ignorado, retornando apenas os feriados nacionais; a busca lê apenas propriedades próprias, então `"__proto__"`, `"constructor"` e afins são códigos desconhecidos como qualquer outro, e não uma exceção. Só os anos de 1900 a 2099 são suportados, o intervalo que os utilitários de dias úteis herdam; um ano fora dele retorna `[]`.
-
-Apenas um feriado estadual por UF é feriado civil pela [Lei nº 9.093/1995](https://www.planalto.gov.br/ccivil_03/leis/l9093.htm), art. 1º, II, que autoriza "a data magna do Estado fixada em lei estadual", no singular; as demais entradas se apoiam em leis estaduais ordinárias e são reportadas por serem observadas na prática. Regras notáveis por estado:
+Retorna os feriados brasileiros de um ano: os nacionais e, com um `stateCode`, também os daquele estado. Aceita um ano ou `{ year, stateCode }` (`GetHolidaysParams`).
-- **SC** — a [Lei SC nº 18.531/2022](http://leis.alesc.sc.gov.br/html/2022/18531_2022_lei.html) transfere os dois feriados estaduais, "Dia do Estado de Santa Catarina" (11/08) e "Dia de Santa Catarina de Alexandria" (25/11), para o domingo subsequente sempre que caem de segunda a sexta, então a segunda-feira 11/08/2025 é dia útil em SC e o feriado cai no domingo 17/08. As duas datas não passaram a ser transferidas juntas. O 11/08 é transferido a partir de 2005, ano em que a [Lei SC nº 13.408/2005](http://leis.alesc.sc.gov.br/html/2005/13408_2005_lei.html) estendeu a cláusula a ele (publicada e em vigor em 15/07/2005), e antes disso fica em 11/08. O 25/11 é transferido a partir de 1999, ano em que a [Lei SC nº 11.213/1999](http://leis.alesc.sc.gov.br/html/1999/11213_1999_lei.html) introduziu a cláusula (publicada e em vigor em 12/11/1999, treze dias antes do 25/11 daquele ano), com um intervalo de um ano: o art. 3º da [Lei SC nº 12.906/2004](http://leis.alesc.sc.gov.br/html/2004/12906_2004_lei.html) revogou aquela lei sem repetir a cláusula, então só o 25/11/2004 fica na data estatutária, até a Lei SC nº 13.408/2005 reinstituir a transferência. Assim, o 25/11/1999 (uma quinta-feira) cai no domingo 28/11, o 25/11/2002 (uma segunda-feira) no domingo 01/12, o 25/11/2004 (uma quinta-feira) não se move, e o 25/11/2005 (uma sexta-feira) cai no domingo 27/11.
-- **DF** — a [Lei distrital nº 72/1989](https://www.sinj.df.gov.br/sinj/Norma/18459/Lei_72_27_12_1989.html), art. 1º parágrafo único, declara Corpus Christi feriado. Com `stateCode: 'DF'` a única entrada de Corpus Christi volta tipada como `"state"` em vez de `"optional"`; ela é substituída, não duplicada.
-- **GO** — a [Lei GO nº 20.756/2020](https://legisla.casacivil.go.gov.br/pesquisa_legislacao/100979/lei-20756), art. 269, II, lista três feriados estaduais: 26/07 (Fundação da Cidade de Goiás), 24/10 (Lançamento da Pedra Fundamental de Goiânia) e 28/10 (Dia do Servidor Público).
-- **AL** — 16/09 é feriado estadual a partir de 2024 ([Lei AL nº 9.358/2024](https://sapl.al.al.leg.br/norma/3117)) e apenas ponto facultativo (`"optional"`) antes disso.
-- **PB** — 26/07 ("Morte de João Pessoa") é emitido apenas até 2015: a [Lei PB nº 10.601/2015](https://sapl.al.pb.leg.br/norma/11988), art. 2º, revogou a sua base.
-- **TO** — 18/03 ("Autonomia do Estado do Tocantins") é emitido apenas até 2008: a [Lei TO nº 2.013/2009](https://www.al.to.leg.br/arquivo/15724) transformou em meramente comemorativo o dispositivo que declarava o feriado.
-
-A data retornada é a legal. O deslocamento de SC acima é o único modelado; o de Acre (feriados de terça a quinta transferidos para a sexta) e os decretos goianos que podem mover 26/07 e 28/10 não são.
+- Cada feriado é um `Holiday` cujo `type` (`HolidayType`) é `"national"`, `"state"`, `"optional"` ou `"religious"`. Os feriados vêm ordenados por data.
+- O "Dia da Consciência Negra", 20/11, é nacional a partir de 2024.
+- As regras por estado (o deslocamento para domingo em SC, o Corpus Christi no DF, datas que deixaram de ser feriado) seguem a lei de cada estado; veja a fonte para a lista.
+- Um `stateCode` desconhecido ou que não é string é ignorado e só os feriados nacionais são retornados.
+- Retorna `[]` quando o ano não é um inteiro de 1900 a 2099, ou quando o argumento não é nem número nem objeto.
```javascript
import { getHolidays } from '@brazilian-utils/brazilian-utils';
@@ -1350,9 +1631,15 @@ getHolidays({ year: 2024, stateCode: 'SP' });
// Inclui feriados nacionais mais feriados estaduais (ex: "Revolução Constitucionalista")
```
+Fonte: `src/get-holidays/constants.ts`, [Lei nº 662/1949](https://www.planalto.gov.br/ccivil_03/leis/l0662.htm), [Lei nº 9.093/1995](https://www.planalto.gov.br/ccivil_03/leis/l9093.htm).
+
### isHoliday
-Verifica se uma data específica é feriado brasileiro. A verificação compara a data local do `targetDate` (ano/mês/dia lidos localmente), não seu instante UTC subjacente. Retorna `false` quando `targetDate` está ausente ou não é um `Date` válido. Um `stateCode` inválido é tratado de duas formas diferentes: uma string que não é um código de estado conhecido é ignorada e só os feriados nacionais são considerados, igual ao `getHolidays`, enquanto um `stateCode` presente que não é uma string (um número, `null`, um objeto) é rejeitado e faz a chamada retornar `false` mesmo em um feriado nacional.
+Verifica se uma data é feriado brasileiro. Aceita `{ targetDate, stateCode? }` (`IsHolidayParams`).
+
+- A verificação usa a data de calendário local de `targetDate`, não o seu instante UTC.
+- `stateCode` também considera os feriados daquele estado. Um código desconhecido é ignorado, como em `getHolidays`.
+- Retorna `false` quando `targetDate` está ausente ou não é um `Date` válido, ou quando `stateCode` está presente e não é string.
```javascript
import { isHoliday } from '@brazilian-utils/brazilian-utils';
@@ -1364,7 +1651,10 @@ isHoliday(); // false
### isBusinessDay
-Verifica se uma data é um dia útil no Brasil. Retorna `false` para sábados, domingos e feriados brasileiros retornados por `getHolidays` para a data local de `value` (ano/mês/dia lidos localmente), a mesma convenção usada por `isHoliday`. `options.includeOptional` (parte de `BusinessDayOptions`, o tipo de opções que todos os utilitários de dias úteis compartilham) tem valor padrão `true`, então feriados do tipo opcional (`Holiday.type === "optional"`, ou seja, Carnaval e Corpus Christi) também contam como dias não úteis; passe `false` para considerar apenas os feriados estatutários. `options.stateCode` também considera os feriados daquele estado; uma string que não é um código de estado conhecido é ignorada, considerando apenas os feriados nacionais, enquanto um `stateCode` presente que não é uma string (um número, `null`, um objeto) é rejeitado e faz a chamada retornar `false` mesmo em um dia de semana comum — a mesma distinção que `isHoliday` faz, e o valor que `addBusinessDays`, `subBusinessDays` e `differenceInBusinessDays` rejeitam com `null`. Um `value` que não é um `Date` válido retorna `false`. Só os anos de 1900 a 2099 são suportados, o intervalo que `getHolidays` calcula; uma data fora dele retorna `false`.
+Verifica se uma data é dia útil no Brasil: não é sábado, domingo nem um feriado que `getHolidays` lista para o seu dia de calendário local.
+
+- **Opções** (`BusinessDayOptions`, as mesmas de todos os utilitários de dias úteis): `includeOptional` (padrão `true`) também conta os feriados `"optional"`, Carnaval e Corpus Christi, como dias não úteis; `stateCode` também conta os feriados daquele estado.
+- Retorna `false` quando `value` não é um `Date` válido ou o seu ano está fora de 1900 a 2099, ou quando `stateCode` está presente e não é string.
```javascript
import { isBusinessDay } from '@brazilian-utils/brazilian-utils';
@@ -1372,7 +1662,7 @@ import { isBusinessDay } from '@brazilian-utils/brazilian-utils';
isBusinessDay(new Date(2024, 0, 2)); // true (terça-feira, não é feriado)
isBusinessDay(new Date(2024, 0, 1)); // false (Ano novo)
isBusinessDay(new Date(2024, 0, 6)); // false (sábado)
-isBusinessDay(new Date(2024, 1, 13)); // false (Carnaval, feriado opcional, conta por padrão)
+isBusinessDay(new Date(2024, 1, 13)); // false (Carnaval, feriado facultativo, conta por padrão)
isBusinessDay(new Date(2024, 1, 13), { includeOptional: false }); // true
isBusinessDay(new Date(2024, 6, 9), { stateCode: 'SP' }); // false (Revolução Constitucionalista)
isBusinessDay(new Date(2024, 6, 9)); // true (feriado estadual ignorado sem stateCode)
@@ -1381,7 +1671,12 @@ isBusinessDay(new Date('not a date')); // false
### addBusinessDays
-Adiciona um número de dias úteis brasileiros a uma data, pulando sábados, domingos e feriados brasileiros exatamente como `isBusinessDay` os define (as mesmas `BusinessDayOptions`: `options.includeOptional`, padrão `true`, e `options.stateCode` funcionam exatamente como lá). A assinatura é a do date-fns: `addBusinessDays(date, amount, options?)`. Retorna um novo `Date`; a `date` de entrada nunca é alterada, e seu horário é preservado no resultado. Um `amount` igual a `0` retorna um novo `Date` igual a `date`, sem alterações, mesmo quando `date` cai em um fim de semana ou feriado, isso reflete o comportamento verificado de [`addBusinessDays(date, 0)` do date-fns](https://date-fns.org/docs/addBusinessDays), que também não avança a entrada para o próximo dia útil. Um `amount` negativo anda para trás, um dia útil por vez, também como no date-fns. Retorna `null` em caso de entrada inválida: uma `date` que não é um `Date` válido, um `amount` que não é um número inteiro finito, ou um `stateCode` que não é uma string; um `options` que não é um objeto é ignorado, exatamente como o `isBusinessDay` o ignora. Só os anos de 1900 a 2099 são suportados, o intervalo que `getHolidays` calcula; uma data fora dele, ou um percurso que sai dele, retorna `null`.
+Soma dias úteis a uma data, pulando sábados, domingos e os feriados que `isBusinessDay` considera. Assinatura: `addBusinessDays(date, amount, options?)`, a mesma do date-fns.
+
+- **Opções** (`BusinessDayOptions`, as mesmas de `isBusinessDay`): `includeOptional` (padrão `true`) também pula Carnaval e Corpus Christi; `stateCode` também pula os feriados daquele estado.
+- Retorna um novo `Date`, com o horário preservado; `date` não é alterado.
+- `amount` igual a `0` retorna a mesma data, mesmo em fim de semana ou feriado. Um `amount` negativo anda para trás.
+- Retorna `null` quando `date` é inválido, `amount` não é um inteiro finito, `stateCode` não é string ou o resultado sai dos anos de 1900 a 2099.
```javascript
import { addBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1397,7 +1692,9 @@ addBusinessDays(new Date(2024, 0, 2), 1.5); // null (não é um número inteiro)
### subBusinessDays
-Subtrai um número de dias úteis brasileiros de uma data: `subBusinessDays(date, amount, options?)` é `addBusinessDays(date, -amount, options)`, e é exatamente assim que a função é implementada, então tudo o que vale acima vale aqui (o horário preservado, a entrada intacta, um `amount` igual a `0` devolvendo a data sem alterações, o intervalo de 1900 a 2099 e os casos de `null`), inclusive o `options.stateCode` e o `options.includeOptional`. Um `amount` negativo anda para frente.
+Subtrai dias úteis de uma data. `subBusinessDays(date, amount, options?)` é `addBusinessDays(date, -amount, options)`.
+
+- As mesmas regras de `addBusinessDays`, `BusinessDayOptions` incluídas. Um `amount` negativo anda para frente.
```javascript
import { subBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1414,7 +1711,12 @@ subBusinessDays(new Date(2024, 0, 2), 1.5); // null (não é um número inteiro)
### differenceInBusinessDays
-Conta o número de dias úteis brasileiros entre duas datas, refletindo a semântica de [`differenceInBusinessDays` do date-fns](https://date-fns.org/docs/differenceInBusinessDays) (verificada em seu código-fonte), inclusive a ordem dos argumentos: `differenceInBusinessDays(laterDate, earlierDate, options?)`. O percurso começa em `earlierDate` e para logo antes de `laterDate`, então `earlierDate` é contado quando ele próprio é um dia útil, `laterDate` nunca é contado, e cada dia útil estritamente entre os dois é contado uma vez. Só a data de calendário de cada `Date` importa, o horário é ignorado. Os dias úteis são determinados exatamente como em `isBusinessDay` (as mesmas `BusinessDayOptions`), inclusive o `options.includeOptional` (padrão `true`) e o `options.stateCode`. O resultado é positivo quando `laterDate` é posterior a `earlierDate` e negativo quando é anterior; duas datas no mesmo dia de calendário retornam `0`. Retorna `null` em caso de entrada inválida: uma data que não é um `Date` válido, ou um `stateCode` que não é uma string; um `options` que não é um objeto é ignorado. Só os anos de 1900 a 2099 são suportados, o intervalo que `getHolidays` calcula; uma data fora dele retorna `null`.
+Conta os dias úteis entre duas datas. Assinatura: `differenceInBusinessDays(laterDate, earlierDate, options?)`, a mesma do date-fns.
+
+- **Opções** (`BusinessDayOptions`, as mesmas de `isBusinessDay`): `includeOptional` (padrão `true`) também pula Carnaval e Corpus Christi; `stateCode` também pula os feriados daquele estado.
+- Conta `earlierDate` quando é dia útil e cada dia útil estritamente entre as duas datas; `laterDate` nunca é contado. O horário é ignorado.
+- O resultado é negativo quando `laterDate` é anterior a `earlierDate`, e `0` no mesmo dia de calendário.
+- Retorna `null` quando uma das datas não é um `Date` válido ou está fora dos anos de 1900 a 2099, ou quando `stateCode` não é string.
```javascript
import { differenceInBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1431,20 +1733,24 @@ differenceInBusinessDays(new Date(), new Date('not a date')); // null
### isValidPassport
-Verifica se um número de passaporte brasileiro é válido (2 letras seguidas de 6 dígitos). Aceita tanto `string` quanto `number`; a entrada é case-insensitive e caracteres não alfanuméricos (espaços, pontos, hífens) são ignorados. Um `number` é aceito por simetria com `formatPassport`/`parsePassport`, mas nunca é válido: a forma decimal de um número nunca começa com as duas letras que um número de passaporte exige.
+Valida um número de passaporte brasileiro: 2 letras seguidas de 6 dígitos.
+
+- Não há dígito verificador, então um número bem formado não é necessariamente um passaporte real.
```javascript
import { isValidPassport } from '@brazilian-utils/brazilian-utils';
isValidPassport('AB123456'); // true
-isValidPassport('ab123456'); // true (case-insensitive)
+isValidPassport('ab123456'); // true (não diferencia maiúsculas de minúsculas)
isValidPassport('AB-123.456'); // true (símbolos são ignorados)
isValidPassport('12345678'); // false
```
+Fonte: [Polícia Federal](https://www.gov.br/pf/pt-br/assuntos/passaporte) e seu [FAQ](https://www.gov.br/pf/pt-br/assuntos/passaporte/ajuda/duvidas_/caderneta/caderneta-numero-onde-fica-e).
+
### formatPassport
-Formata um número de passaporte brasileiro (maiúsculas, sem símbolos, limitado a 8 caracteres). Uma entrada que não seja `string` retorna uma string vazia.
+Formata um número de passaporte brasileiro: maiúsculas, sem símbolos, limitado a 8 caracteres. É a mesma operação de `parsePassport`, da qual é um alias.
```javascript
import { formatPassport } from '@brazilian-utils/brazilian-utils';
@@ -1455,7 +1761,7 @@ formatPassport('AB-123.456'); // 'AB123456'
### parsePassport
-Remove todos os caracteres não alfanuméricos de um número de passaporte, converte para maiúsculas e limita o resultado a 8 caracteres. Uma entrada que não seja `string` retorna uma string vazia.
+Remove todos os caracteres não alfanuméricos de um número de passaporte, converte para maiúsculas e limita o resultado a 8 caracteres.
```javascript
import { parsePassport } from '@brazilian-utils/brazilian-utils';
@@ -1466,7 +1772,7 @@ parsePassport(' AB 123 456 '); // 'AB123456'
### generatePassport
-Gera um número de passaporte brasileiro válido aleatoriamente. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um número de passaporte brasileiro válido aleatório.
```javascript
import { generatePassport } from '@brazilian-utils/brazilian-utils';
@@ -1478,7 +1784,10 @@ generatePassport(); // 'RY393097'
### isValidCnh
-Valida se a CNH é válida. Espaços, pontos e hífens ao redor/entre os dígitos são ignorados, mas qualquer outro caractere, uma letra em especial, invalida o valor. Um valor cujos 11 dígitos são todos iguais é rejeitado antes do cálculo dos dígitos verificadores, então `'11111111111'` é inválido.
+Valida uma CNH. Espaços, pontos e hífens são ignorados; qualquer outro caractere invalida o valor.
+
+- Um valor cujos 11 dígitos são todos iguais é rejeitado, então `'11111111111'` é inválido.
+- O primeiro dígito verificador mantém o resto 1 como `1`, como nos números reais de registro. A Resolução CONTRAN nº 886/2021 diz `0`.
```javascript
import { isValidCnh } from '@brazilian-utils/brazilian-utils';
@@ -1488,9 +1797,13 @@ isValidCnh('000000001-19'); // true (hífen antes dos dígitos verificadores)
isValidCnh('ab00000000119'); // false (letras são rejeitadas)
```
+Fonte: [Resolução CONTRAN nº 886/2021, art. 4º](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/Resolucao8862021F.pdf); pesos conforme o [siga0984](https://siga0984.wordpress.com/2019/05/01/algoritmos-validacao-de-cnh/).
+
### formatCnh
-Formata a CNH. `options.pad` (parte de `FormatCnhOptions`) completa o valor com zeros à esquerda até os 11 dígitos antes de aplicar a máscara (padrão `false`).
+Formata uma CNH.
+
+- **Opções** (`FormatCnhOptions`): `pad` completa o valor com zeros à esquerda até os 11 dígitos antes de aplicar a máscara (padrão `false`).
```javascript
import { formatCnh } from '@brazilian-utils/brazilian-utils';
@@ -1501,7 +1814,7 @@ formatCnh('2650306461', { pad: true }); // 026503064-61
### parseCnh
-Remove a formatação da CNH, mantém apenas os dígitos e limita o resultado a 11 dígitos. Retorna `''` quando não há nenhum dígito.
+Remove a formatação da CNH, mantém apenas os dígitos e limita o resultado a 11 dígitos.
```javascript
import { parseCnh } from '@brazilian-utils/brazilian-utils';
@@ -1511,7 +1824,7 @@ parseCnh('026503064-61'); // '02650306461'
### generateCnh
-Gera uma CNH válida aleatória. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera uma CNH válida aleatória.
```javascript
import { generateCnh } from '@brazilian-utils/brazilian-utils';
@@ -1523,7 +1836,9 @@ generateCnh(); // '02650306461'
### isValidLegalNature
-Valida se um código de natureza jurídica existe na lista oficial. A tabela segue a "Natureza Jurídica 2021" do IBGE/CONCLA: os 92 códigos em vigor mais os 8 que uma revisão anterior da tabela extinguiu, mantidos porque continuam aparecendo em registros feitos enquanto valiam. Use `getLegalNature` para distinguir os dois: um código extinto volta com `legacy: true` e o `currentCode` a que corresponde hoje. Somente os caracteres de máscara usuais (hífens, pontos, espaços) são tolerados ao redor dos 4 dígitos, então `'2062a'` é rejeitado em vez de ser lido como `'2062'`.
+Valida se um código de natureza jurídica existe na lista oficial, a tabela "Natureza Jurídica 2021" do IBGE/CONCLA. Somente hífens, pontos e espaços são tolerados ao redor dos 4 dígitos.
+
+- Os 92 códigos em vigor são aceitos, mais os 8 que uma revisão anterior extinguiu. `getLegalNature` distingue os dois (`legacy: true`).
```javascript
import { isValidLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1533,9 +1848,13 @@ isValidLegalNature('2208'); // true (extinto por uma revisão anterior, ainda ac
isValidLegalNature('9999'); // false
```
+Fonte: [CONCLA, Natureza Jurídica 2021](https://concla.ibge.gov.br/estrutura/natjur-estrutura/natureza-juridica-2021) e seu [PDF de estrutura detalhada](https://concla.ibge.gov.br/images/concla/documentacao/CONCLA-TNJ2021-EstruturaDetalhada.pdf).
+
### formatLegalNature
-Formata um código de natureza jurídica. `options.pad` (parte de `FormatLegalNatureOptions`) funciona exatamente como em `formatCpf`/`formatCep`: com o padrão `false` a máscara é aplicada progressivamente, até onde o valor vai; com `true` o valor é primeiro completado com zeros à esquerda até os 4 dígitos de um código completo. Use `isValidLegalNature` para verificar um código.
+Formata um código de natureza jurídica. Use `isValidLegalNature` para verificar um código.
+
+- **Opções** (`FormatLegalNatureOptions`): `pad` primeiro completa o valor com zeros à esquerda até os 4 dígitos de um código completo (padrão `false`).
```javascript
import { formatLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1558,7 +1877,7 @@ parseLegalNature('206-2'); // '2062'
### generateLegalNature
-Gera um código de natureza jurídica válido aleatório. Apenas os 92 códigos em vigor são sorteados, nunca um dos 8 que uma revisão anterior extinguiu. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um código de natureza jurídica válido aleatório. Apenas os 92 códigos em vigor são sorteados, nunca um extinto.
```javascript
import { generateLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1568,9 +1887,10 @@ generateLegalNature(); // '2062'
### getLegalNature
-Busca um código de natureza jurídica na tabela oficial do IBGE/CONCLA. A entrada também traz a categoria do CONCLA em que o código está listado, dada pelo seu primeiro dígito. Nenhum código de natureza jurídica começa com zero, esse primeiro dígito é a categoria (1 a 5), então aqui nada é completado: um número e a string dos mesmos dígitos são lidos de forma idêntica.
+Busca um código de natureza jurídica na tabela oficial do IBGE/CONCLA. Retorna `null` para um código desconhecido.
-Um código que uma revisão anterior da tabela extinguiu continua sendo encontrado, porque segue aparecendo em registros feitos enquanto valia, e volta com `legacy: true` e o `currentCode` a que corresponde hoje, conforme as planilhas de correspondência do CONCLA. Os 92 códigos em vigor têm `legacy: false` e nenhum `currentCode`.
+- A entrada (`LegalNature`) também traz a categoria do CONCLA do código, dada pelo seu primeiro dígito.
+- Um código que uma revisão anterior extinguiu retorna com `legacy: true` e o `currentCode` a que corresponde hoje, ou `currentCode: null` quando não há sucessor. Os códigos em vigor têm `legacy: false` e nenhum `currentCode`.
| Código extinto | Descrição | Corresponde a |
| --- | --- | --- |
@@ -1607,9 +1927,13 @@ getLegalNature(206.2)?.category.description; // 'Entidades Empresariais'
getLegalNature('0000'); // null
```
+Fonte: [CONCLA, Natureza Jurídica 2021](https://concla.ibge.gov.br/estrutura/natjur-estrutura/natureza-juridica-2021).
+
### getLegalNatures
-Retorna o mapa de naturezas jurídicas indexado pelo código. Por padrão apenas os 92 códigos da tabela CONCLA 2021, os em vigor, são listados; passe `{ includeLegacy: true }` (`GetLegalNaturesParams`) para somar os 8 que uma revisão anterior da tabela extinguiu.
+Retorna o mapa de naturezas jurídicas indexado pelo código. Por padrão apenas os 92 códigos em vigor são listados.
+
+- **Opções** (`GetLegalNaturesParams`): `includeLegacy` (padrão `false`) soma os 8 códigos extintos.
```javascript
import { getLegalNatures } from '@brazilian-utils/brazilian-utils';
@@ -1624,7 +1948,11 @@ getLegalNatures({ includeLegacy: true })['2208']; // 'Entidade Binacional Itaipu
### getLegalNaturesByCategory
-Retorna todas as naturezas jurídicas de uma categoria do CONCLA, o grupo dado pelo primeiro dígito do código: `1` Administração Pública, `2` Entidades Empresariais, `3` Entidades sem Fins Lucrativos, `4` Pessoas Físicas e `5` Organizações Internacionais e Outras Instituições Extraterritoriais. A categoria é aceita como string ou como número, as entradas voltam ordenadas por código e uma categoria desconhecida devolve `[]`. Por padrão apenas os códigos em vigor são listados; passe `{ includeLegacy: true }` (`GetLegalNaturesByCategoryOptions`) para somar os códigos extintos da categoria, na ordem dos códigos.
+Retorna todas as naturezas jurídicas de uma categoria do CONCLA, o grupo dado pelo primeiro dígito do código. A categoria é aceita como string ou como número.
+
+- Categorias: `1` Administração Pública, `2` Entidades Empresariais, `3` Entidades sem Fins Lucrativos, `4` Pessoas Físicas e `5` Organizações Internacionais e Outras Instituições Extraterritoriais.
+- **Opções** (`GetLegalNaturesByCategoryOptions`): `includeLegacy` (padrão `false`) soma os códigos extintos da categoria.
+- As entradas retornam ordenadas por código. Uma categoria desconhecida retorna `[]`.
```javascript
import { getLegalNaturesByCategory } from '@brazilian-utils/brazilian-utils';
@@ -1646,7 +1974,10 @@ getLegalNaturesByCategory('9'); // []
### isValidVoterId
-Valida se um título de eleitor é válido. Aceita tanto o título padrão de 12 dígitos quanto o título de 13 dígitos emitido por São Paulo (UF `01`) e Minas Gerais (UF `02`). Espaços e pontos são aceitos ao redor e entre os grupos `0000 0000 00 00`, mas qualquer outro caractere, uma letra em especial, invalida o valor.
+Valida um título de eleitor. Aceita o título padrão de 12 dígitos e o título de 13 dígitos expedido por São Paulo (UF `01`) e Minas Gerais (UF `02`).
+
+- Um título é um número sequencial de 8 dígitos, um código de unidade federativa de 2 dígitos (`01` a `28`) e 2 dígitos verificadores.
+- Espaços e pontos são aceitos ao redor e entre os grupos. Qualquer outro caractere, inclusive um hífen, invalida o valor.
```javascript
import { generateVoterId, isValidVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1654,11 +1985,19 @@ import { generateVoterId, isValidVoterId } from '@brazilian-utils/brazilian-util
const voterId = generateVoterId('SP');
isValidVoterId(voterId); // true
+isValidVoterId('102385010671'); // true (12 dígitos)
+isValidVoterId('1234567880191'); // true (13 dígitos, São Paulo)
+isValidVoterId('123456780124'); // false (dígitos verificadores inválidos)
```
+Fonte: [Resolução TSE nº 23.659/2021, art. 36](https://www.tse.jus.br/legislacao/compilada/res/2021/resolucao-no-23-659-de-26-de-outubro-de-2021), [brutils](https://github.com/brazilian-utils/python/blob/main/brutils/voter_id.py) e [siga0984](https://siga0984.wordpress.com/2019/05/01/algoritmos-validacao-de-titulo-de-eleitor/).
+
### formatVoterId
-Formata um título de eleitor. Usa por padrão o agrupamento de 12 dígitos `0000 0000 00 00`; o agrupamento de 13 dígitos `0000 0000 0 00 00` só é usado quando o valor sanitizado tem mais de 12 dígitos **e** o código de unidade federativa (o 10º e o 11º dígitos) é `01` (São Paulo) ou `02` (Minas Gerais), os dois estados cujos títulos podem ter um número sequencial de 9 dígitos.
+Formata um título de eleitor com o agrupamento de 12 dígitos `0000 0000 00 00`.
+
+- O agrupamento de 13 dígitos `0000 0000 0 00 00` só é usado quando o valor tem mais de 12 dígitos e o código da UF (o 10º e o 11º dígitos) é `01` ou `02`.
+- Os dígitos além da última posição do padrão são descartados.
```javascript
import { formatVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1680,7 +2019,10 @@ parseVoterId('1234 5678 8 01 91'); // '1234567880191' (título de 13 dígitos SP
### generateVoterId
-Gera um título de eleitor válido aleatório. Você pode opcionalmente informar a UF; uma UF desconhecida usa `"ZZ"` (título emitido no exterior) em vez de lançar erro. Usa `Math.random()` internamente, então não é criptograficamente seguro.
+Gera um título de eleitor válido aleatório. O argumento opcional `state` (`StateCode`, ou `"ZZ"` para um título expedido no exterior) define o código de unidade federativa.
+
+- Uma UF desconhecida, ou um valor que não seja string, usa `"ZZ"` (UF `28`).
+- O resultado sempre tem 12 dígitos, nunca a forma de 13 dígitos de São Paulo ou Minas Gerais.
```javascript
import { generateVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1694,23 +2036,30 @@ generateVoterId('XX'); // usa "ZZ" em vez de lançar erro
### isValidCns
-Verifica se um número de CNS (Cartão Nacional de Saúde) é válido, o identificador único do usuário do SUS (Sistema Único de Saúde). Cartões definitivos (iniciados em 1 ou 2) são validados sobre uma base embutida de 11 dígitos derivada do PIS/PASEP/NIS, ponderada de 15 até 5; quando o dígito bruto resulta em 10, o DATASUS soma 2 à soma ponderada, recalcula o dígito e marca o cartão com o sufixo `001` em vez de `000`. Cartões provisórios (iniciados em 7, 8 ou 9) são validados por uma soma ponderada única (pesos de 15 a 1) que deve ser múltipla de 11. O valor precisa vir escrito como os 15 dígitos, opcionalmente separados nos grupos impressos de 3-4-4-4 por espaço em branco, `.`, `-` ou `/`, os caracteres de máscara intercambiáveis que `isValidCpf` e `isValidCnpj` aceitam, inclusive uma sequência deles entre dois grupos; letras no meio dos dígitos, ou um separador dentro de um grupo, são rejeitadas em vez de ignoradas.
+Valida um número de CNS (Cartão Nacional de Saúde), o identificador do SUS (Sistema Único de Saúde) de um usuário, profissional ou estabelecimento de saúde. O valor precisa ser os 15 dígitos, opcionalmente separados nos grupos impressos de 3-4-4-4 por espaço, `.`, `-` ou `/`.
-As duas rotinas vêm da [página de validação de CNS da ANVISA](https://rni-docs.anvisa.gov.br/docs/regras_gerais/validacoes/validacaoCNS/), que fica atrás de um filtro de bots e responde HTTP 403 a clientes que não sejam navegadores. A [página do e-SUS APS](https://integracao.esusab.ufsc.br/ledi/documentacao/regras/algoritmo_CNS.html) documenta o mesmo algoritmo e é acessível sem navegador, mas aplica a rotina de provisórios a números iniciados em 5, 7, 8 ou 9; esta implementação segue a ANVISA e rejeita um número iniciado em 5 mesmo quando a soma ponderada fecha.
+- Cartões definitivos começam com 1 ou 2, provisórios com 7, 8 ou 9; cada um tem sua própria regra de módulo 11.
+- Um número iniciado em 5 é rejeitado, seguindo a ANVISA.
```javascript
import { isValidCns } from '@brazilian-utils/brazilian-utils';
isValidCns('123456789010000'); // true (definitivo)
+isValidCns('100000000060018'); // true (definitivo, dígito bruto 10, sufixo 001)
isValidCns('700000000000005'); // true (provisório)
isValidCns('123.4567-8901/0000'); // true (qualquer um dos caracteres de máscara)
+isValidCns('123456789010001'); // false (dígito verificador inválido)
isValidCns('12345678901'); // false (tamanho inválido)
isValidCns('abc123456789010000'); // false (não escrito como um CNS)
```
+Fonte: [página de validação de CNS da ANVISA](https://rni-docs.anvisa.gov.br/docs/regras_gerais/validacoes/validacaoCNS/) e a [página do e-SUS APS](https://integracao.esusab.ufsc.br/ledi/documentacao/regras/algoritmo_CNS.html).
+
### formatCns
-Formata um número de CNS (Cartão Nacional de Saúde) nos grupos de exibição usuais de 3-4-4-4 dígitos separados por espaço. `options.pad` (parte de `FormatCnsOptions`) preenche o valor com zeros à esquerda até as 15 posições do padrão antes de aplicar a máscara (padrão `false`).
+Formata um número de CNS (Cartão Nacional de Saúde) nos grupos de exibição usuais de 3-4-4-4 dígitos separados por espaço.
+
+- **Opções** (`FormatCnsOptions`): `pad` completa o valor com zeros à esquerda até as 15 posições do padrão antes de aplicar a máscara (padrão `false`).
```javascript
import { formatCns } from '@brazilian-utils/brazilian-utils';
@@ -1722,7 +2071,7 @@ formatCns('89010001', { pad: true }); // '000 0000 8901 0001'
### parseCns
-Remove a formatação do CNS (Cartão Nacional de Saúde), mantém apenas os dígitos e limita o resultado a 15 dígitos. Um valor parcial passa adiante até onde vai, então também dá para tirar a máscara de um campo ainda sendo digitado; use `isValidCns` para verificar o número em si.
+Remove a formatação do CNS (Cartão Nacional de Saúde), mantém apenas os dígitos e limita o resultado a 15 dígitos.
```javascript
import { parseCns } from '@brazilian-utils/brazilian-utils';
@@ -1734,9 +2083,25 @@ parseCns('123 4567 8901 0000'); // '123456789010000'
### isValidCertidao
-Verifica se a matrícula de uma certidão de registro civil (nascimento, casamento, óbito e os demais atos mantidos por uma serventia de registro civil das pessoas naturais) é válida. A matrícula tem 32 dígitos distribuídos em 6 (CNS da serventia) + 2 (acervo) + 2 (serviço) + 4 (ano) + 1 (tipo do livro) + 5 (livro) + 3 (folha) + 7 (termo) + 2 (dígitos verificadores), e os dois dígitos verificadores usam módulo 11 com os pesos ciclando de 2 a 10 e voltando por 0: o primeiro cálculo começa em 2 sobre os 30 dígitos da base, o segundo em 1 sobre os 31 dígitos que incluem o primeiro dígito verificador, e nos dois um resto 10 é lido como 1. Aceita os caracteres de máscara usuais e espaços entre e ao redor dos grupos. O layout é o publicado atualmente no [art. 473 do Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243) (Provimento CNJ nº 149/2023), com o inciso II e os §§ 1º e 3º a 5º na redação do Provimento CN nº 237/2026 e o restante do artigo, inclusive o § 2º, na do Provimento CN nº 182/2024; a própria matrícula foi instituída pelo já revogado [Provimento CNJ nº 2/2009](https://atos.cnj.jus.br/atos/detalhar/1311) e ganhou sua estrutura de dígitos no também revogado [Provimento CNJ nº 3/2009, art. 7º](https://atos.cnj.jus.br/atos/detalhar/1310). Os dígitos verificadores estão detalhados em [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e implementado pelo [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts) e pelo [validator-docs](https://github.com/geekcom/validator-docs/blob/master/src/validator-docs/Rules/Certidao.php).
+Valida a matrícula de uma certidão de registro civil (nascimento, casamento, óbito e os demais atos de um registro civil das pessoas naturais). Só uma string é aceita: os 32 dígitos de uma matrícula são mais do que um número JavaScript comporta.
+
+A matrícula tem 32 dígitos, impressos como `000000 00 00 0000 0 00000 000 0000000 00`:
+
+| Dígitos | Campo |
+| --- | --- |
+| 6 | CNS da serventia |
+| 2 | acervo |
+| 2 | serviço, sempre `55` |
+| 4 | ano |
+| 1 | tipo do livro |
+| 5 | livro |
+| 3 | folha |
+| 7 | termo |
+| 2 | dígitos verificadores |
-Os dígitos do serviço são fixos em `55`, o código que o [art. 473, III](https://atos.cnj.jus.br/atos/detalhar/5243) atribui ao registro civil das pessoas naturais, então uma matrícula com qualquer outro par na nona e décima posições é rejeitada por mais que os dígitos verificadores confiram. O dígito do tipo de livro sempre precisa nomear um dos nove tipos de livro (o mesmo `CertidaoType` retornado por `getCertidaoInfo`), então uma matrícula cujo dígito é `0` é rejeitada por mais que os dígitos verificadores confiram, do mesmo jeito que `getCertidaoInfo` devolve `null` para ela. `options.accept` (parte de `IsValidCertidaoOptions`) restringe ainda mais aos tipos listados; o padrão é aceitar todos os tipos, e um valor que não seja um array volta para esse padrão. Só uma string é aceita: os 32 dígitos de uma matrícula são mais do que um número JavaScript comporta.
+- **Opções** (`IsValidCertidaoOptions`): `accept` restringe os tipos de livro válidos (`CertidaoType`) aos listados (padrão: todos os tipos).
+- O serviço precisa ser `55`, e o dígito do tipo de livro precisa ser um dos nove livros (`0` é rejeitado).
+- Aceita o valor com ou sem máscara, com espaços entre e ao redor dos grupos.
```javascript
import { isValidCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1750,9 +2115,14 @@ isValidCertidao('104539 01 55 2013 1 00012 021 0000123 21', { accept: ['birth']
isValidCertidao('104539 01 55 2013 1 00012 021 0000123 21', { accept: ['death'] }); // false
```
+Fonte: [art. 473 do Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243); dígitos verificadores conforme o [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e o [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts).
+
### formatCertidao
-Formata a matrícula de uma certidão de registro civil na máscara impressa do Provimento, os 32 dígitos agrupados em 6 2 2 4 1 5 3 7 2 e separados por espaços. `options.pad` (parte de `FormatCertidaoOptions`) preenche o valor com zeros à esquerda até 32 dígitos (padrão `false`). A máscara é a do [art. 473 do Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243). Um número é aceito e lido como a string dos seus dígitos, como no `formatCpf`, mas uma matrícula completa de 32 dígitos precisa ser uma string: essa quantidade de dígitos é mais do que um número JavaScript comporta com exatidão. Em tempo de execução o valor é lido pelos seus dígitos e a máscara é aplicada até onde eles vão, como em todo formatador deste pacote, então uma matrícula parcial ainda sendo digitada é mascarada progressivamente.
+Formata a matrícula de uma certidão de registro civil na máscara impressa do art. 473. Os 32 dígitos são agrupados em 6 2 2 4 1 5 3 7 2 e separados por espaços.
+
+- **Opções** (`FormatCertidaoOptions`): `pad` completa o valor com zeros à esquerda até 32 dígitos (padrão `false`).
+- Um número é aceito, mas uma matrícula completa de 32 dígitos precisa ser uma string.
```javascript
import { formatCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1763,9 +2133,11 @@ formatCertidao('1552010100020112000012087', { pad: true }); // 000000 01 55 2010
formatCertidao(104539015520); // 104539 01 55 20 (um número é lido como a string dos seus dígitos)
```
+Fonte: [art. 473 do Código Nacional de Normas](https://atos.cnj.jus.br/atos/detalhar/5243).
+
### parseCertidao
-Remove a formatação da matrícula de uma certidão de registro civil, mantém apenas os dígitos e limita o resultado a 32 dígitos. Isso só tira a máscara: use `isValidCertidao` para verificar a matrícula e `getCertidaoInfo` para ler os campos dela.
+Remove a formatação da matrícula de uma certidão de registro civil, mantém apenas os dígitos e limita o resultado a 32 dígitos.
```javascript
import { parseCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1776,7 +2148,25 @@ parseCertidao('104539 01 55 2013 1 00012 021 0000123 21');
### getCertidaoInfo
-Extrai os campos da matrícula de uma certidão de registro civil, retornando `null` quando a matrícula é inválida, o que inclui um código de livro que não é um dos nove livros. Um serviço diferente do `55` que o art. 473, III fixa para o registro civil das pessoas naturais também resulta em `null`. O [art. 473, V do Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243) lista os códigos de 1 a 7; nenhum texto primário do CNJ acessível hoje publica os outros dois, inclusive o Anexo IV do revogado Provimento CNJ nº 63/2017, que lista os mesmos sete. Os códigos 8 (emancipação) e 9 (interdição) vêm das referências em que a regra do dígito verificador se apoia: o [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e o [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts) publicam a lista dos nove livros. Eles são mantidos porque matrículas com eles circulam. Só uma string é aceita: os 32 dígitos de uma matrícula são mais do que um número JavaScript comporta.
+Extrai os campos da matrícula de uma certidão de registro civil. Aceita as mesmas formas de entrada de `isValidCertidao` e retorna `null` quando a matrícula é inválida.
+
+- Retorna `null` também para um serviço diferente de `55` e para um código de livro fora de 1 a 9.
+- O art. 473, V lista apenas os códigos de livro de 1 a 7. Os códigos 8 (emancipação) e 9 (interdição) também são aceitos.
+
+O resultado `CertidaoInfo` traz:
+
+| Chave | Descrição |
+| --- | --- |
+| `registryCns` | O CNS (Código Nacional de Serventia) de 6 dígitos da serventia que lavrou o ato. |
+| `acervo` | Acervo a que o livro pertence: `"01"` acervo próprio, `"02"` em diante um por acervo incorporado. O art. 473, §§ 3º a 5º separa os incorporados pela data em que a serventia de origem foi extinta ou desativada. Até 31/12/2009: o CNS da unidade incorporadora e um código de acervo a partir de `"02"`, um por incorporação. A partir de 01/01/2010: o CNS da própria unidade incorporada e o código `"01"`, considerado acervo próprio dessa unidade. Um acervo fracionado entre duas ou mais serventias sucessoras leva o CNS próprio de cada sucessora com o código `"02"`. |
+| `service` | Serviço prestado pela serventia, sempre `"55"`, o registro civil das pessoas naturais. |
+| `year` | Ano do registro, com 4 dígitos. |
+| `type` | Livro a que o ato pertence: `"birth"`, `"marriage"`, `"religious-marriage"`, `"death"`, `"stillbirth"`, `"banns"`, `"other"`, `"emancipation"` ou `"interdiction"`. |
+| `typeCode` | Código bruto do livro, de 1 a 9, como impresso na décima quinta posição da matrícula. |
+| `book` | Número do livro, com 5 dígitos e zeros à esquerda. |
+| `page` | Número da folha, com 3 dígitos e zeros à esquerda. |
+| `term` | Número do termo, com 7 dígitos e zeros à esquerda. |
+| `checkDigits` | Os 2 dígitos verificadores módulo 11 da matrícula. |
```javascript
import { getCertidaoInfo } from '@brazilian-utils/brazilian-utils';
@@ -1798,26 +2188,15 @@ getCertidaoInfo('104539 01 55 2013 1 00012 021 0000123 21');
getCertidaoInfo('invalid'); // null
```
-O resultado `CertidaoInfo` traz:
-
-| Chave | Descrição |
-| --- | --- |
-| `registryCns` | O CNS (Código Nacional de Serventia) de 6 dígitos da serventia que lavrou o ato. |
-| `acervo` | Acervo a que o livro pertence: `"01"` acervo próprio, `"02"` em diante um por acervo incorporado. O [art. 473, §§ 3º a 5º](https://atos.cnj.jus.br/atos/detalhar/5243) separa os incorporados pela data em que a serventia de origem foi extinta ou desativada: até 31/12/2009 a matrícula leva o CNS da unidade incorporadora e um código de acervo a partir de `"02"`, um por incorporação; a partir de 1º/01/2010 leva o CNS da própria unidade incorporada e o código `"01"`, considerado acervo próprio dessa unidade; e um acervo fracionado entre duas ou mais serventias sucessoras leva o CNS próprio de cada sucessora com o código `"02"`. |
-| `service` | Serviço prestado pela serventia, sempre `"55"`, o registro civil das pessoas naturais. |
-| `year` | Ano do registro, com 4 dígitos. |
-| `type` | Livro a que o ato pertence: `"birth"`, `"marriage"`, `"religious-marriage"`, `"death"`, `"stillbirth"`, `"banns"`, `"other"`, `"emancipation"` ou `"interdiction"`. |
-| `typeCode` | Código bruto do livro, de 1 a 9, como impresso na décima quinta posição da matrícula. |
-| `book` | Número do livro, com 5 dígitos e zeros à esquerda. |
-| `page` | Número da folha, com 3 dígitos e zeros à esquerda. |
-| `term` | Número do termo, com 7 dígitos e zeros à esquerda. |
-| `checkDigits` | Os 2 dígitos verificadores módulo 11 da matrícula. |
+Fonte: [art. 473 do Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243); códigos de livro 8 e 9 conforme o [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e o [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts).
## CEI, CNO e CAEPF
### isValidCei
-Verifica se um número de CEI (Cadastro Específico do INSS) é válido. O CEI identifica o empregador sem CNPJ, como uma obra ou um produtor rural: 12 dígitos impressos como `00.000.00000/00`, sendo o último um dígito verificador calculado sobre os 11 dígitos da base com os pesos 7, 4, 1, 8, 5, 2, 1, 6, 3, 7 e 4. Aceita os caracteres de máscara usuais e espaços entre e ao redor dos grupos, inclusive uma sequência deles entre dois grupos. A Receita Federal não publica essa regra de dígito verificador, então ela segue as implementações de referência do [yii2-br-validator](https://github.com/yiibr/yii2-br-validator/blob/master/src/CeiValidator.php) e do [Bigai.Documentos.Brasil](https://github.com/marcos-cruz/Documento/blob/master/src/Bigai.Documentos.Brasil/Cei/Cei.cs), conferida contra os [dados abertos do Cadastro Nacional de Obras (CNO)](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno) da Receita Federal.
+Valida um número de CEI (Cadastro Específico do INSS). O CEI identifica o empregador sem CNPJ, como uma obra ou um produtor rural.
+
+- Layout: 12 dígitos impressos como `00.000.00000/00`, 11 dígitos de base e um dígito verificador.
```javascript
import { isValidCei } from '@brazilian-utils/brazilian-utils';
@@ -1829,9 +2208,13 @@ isValidCei('24.985.96743/68'); // false (dígito verificador inválido)
isValidCei('000000000000'); // false (dígitos repetidos)
```
+Fonte: [yii2-br-validator](https://github.com/yiibr/yii2-br-validator/blob/master/src/CeiValidator.php), [Bigai.Documentos.Brasil](https://github.com/marcos-cruz/Documento/blob/master/src/Bigai.Documentos.Brasil/Cei/Cei.cs) e a [base de dados aberta do CNO](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno).
+
### formatCei
-Formata um número de CEI (Cadastro Específico do INSS) na máscara usual `00.000.00000/00`, a mesma em que as implementações de referência do dígito verificador concordam (a Receita Federal não a publica). Formata progressivamente, até onde os dígitos informados alcançarem, então também pode ser usada como máscara de digitação. `options.pad` (parte de `FormatCeiOptions`) preenche à esquerda com zeros até 12 dígitos (padrão `false`).
+Formata um número de CEI (Cadastro Específico do INSS) na máscara usual `00.000.00000/00`.
+
+- **Opções** (`FormatCeiOptions`): `pad` completa o valor com zeros à esquerda até 12 dígitos (padrão `false`).
```javascript
import { formatCei } from '@brazilian-utils/brazilian-utils';
@@ -1843,7 +2226,7 @@ formatCei('249', { pad: true }); // 00.000.00002/49
### parseCei
-Remove a formatação do CEI (Cadastro Específico do INSS), mantém apenas os dígitos e limita o resultado a 12 dígitos. Um valor parcial passa adiante até onde vai; use `isValidCei` para verificar o número em si.
+Remove a formatação do CEI (Cadastro Específico do INSS), mantém apenas os dígitos e limita o resultado a 12 dígitos.
```javascript
import { parseCei } from '@brazilian-utils/brazilian-utils';
@@ -1853,7 +2236,9 @@ parseCei('27.729.71181/87'); // '277297118187'
### isValidCno
-Verifica se um número de CNO (Cadastro Nacional de Obras) é válido. O CNO substituiu o CEI para obras e manteve a mesma numeração, então uma obra registrada sob um CEI antigo conserva o número e os dois cadastros são validados do mesmo jeito: 12 dígitos impressos como `00.000.00000/00`, com o dígito verificador calculado sobre os 11 dígitos da base. A Receita Federal não publica a regra do dígito verificador; ela foi confirmada contra os [dados abertos do Cadastro Nacional de Obras (CNO)](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno) da Receita Federal: todas as obras do recorte de Minas Gerais desse conjunto passam nesta verificação. A página do catálogo publica apenas a descrição e os links de download do conjunto, não esse resultado.
+Valida um número de CNO (Cadastro Nacional de Obras). O CNO substituiu o CEI para obras e manteve a mesma numeração.
+
+- Mesmas regras de `isValidCei`.
```javascript
import { isValidCno } from '@brazilian-utils/brazilian-utils';
@@ -1865,9 +2250,13 @@ isValidCno('110840168063'); // false (dígito verificador inválido)
isValidCno('000000000000'); // false (dígitos repetidos)
```
+Fonte: [página do CNO da Receita Federal](https://www.gov.br/receitafederal/pt-br/assuntos/orientacao-tributaria/cadastros/cno) e a [base de dados aberta do CNO](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno).
+
### formatCno
-Formata um número de CNO (Cadastro Nacional de Obras). O CNO manteve a numeração do CEI, então os dois compartilham a mesma máscara de 12 dígitos, `00.000.00000/00`, a mesma em que as implementações de referência do dígito verificador concordam (a Receita Federal não a publica). Formata progressivamente, até onde os dígitos informados alcançarem, então também pode ser usada como máscara de digitação. `options.pad` (parte de `FormatCnoOptions`) preenche à esquerda com zeros até 12 dígitos (padrão `false`).
+Formata um número de CNO (Cadastro Nacional de Obras).
+
+- Mesmas regras de `formatCei`: a máscara `00.000.00000/00`, com `pad` em `FormatCnoOptions`.
```javascript
import { formatCno } from '@brazilian-utils/brazilian-utils';
@@ -1879,7 +2268,7 @@ formatCno('979', { pad: true }); // 00.000.00009/79
### parseCno
-Remove a formatação do CNO (Cadastro Nacional de Obras), mantém apenas os dígitos e limita o resultado a 12 dígitos, a numeração que o CNO herdou do CEI. Um valor mais curto passa adiante até onde vai; use `isValidCno` para verificar o número em si.
+Remove a formatação do CNO (Cadastro Nacional de Obras), mantém apenas os dígitos e limita o resultado a 12 dígitos, a numeração que o CNO herdou do CEI.
```javascript
import { parseCno } from '@brazilian-utils/brazilian-utils';
@@ -1889,7 +2278,10 @@ parseCno('11.113.01373/68'); // '111130137368'
### isValidCaepf
-Verifica se um número de CAEPF (Cadastro de Atividade Econômica da Pessoa Física) é válido. O CAEPF substituiu o CEI para a pessoa física que contrata empregados: 14 dígitos impressos como `000.000.000/000-00`, formados pela base de 9 dígitos do CPF do titular, um número de ordem de 3 dígitos para os vários cadastros do mesmo titular e 2 dígitos verificadores. Os dois dígitos verificadores são o módulo 11 do CNPJ na formulação da referência citada: os pesos vão de 9 até 2 da direita para a esquerda e o dígito é o próprio resto, com o resto 10 lido como 0 — o mesmo dígito que os pesos de 2 a 9 do CNPJ com `11 - resto` produzem. O par resultante é somado a 12, com retorno a zero acima de 99. Uma base cujos 12 dígitos são todos iguais é rejeitada antes do cálculo dos dígitos verificadores, do mesmo jeito que `isValidCei` e `isValidCno` rejeitam um número de CEI/CNO repetido, então o `00000000000012`, que de resto é bem formado, é inválido. A Receita Federal não publica o layout nem a regra dos dígitos verificadores: os dois estão descritos em [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e são implementados do mesmo jeito pelo [brazilian-values](https://github.com/VitorLuizC/brazilian-values/blob/master/src/validators/isCAEPF.ts).
+Valida um número de CAEPF (Cadastro de Atividade Econômica da Pessoa Física). O CAEPF substituiu o CEI para a pessoa física que contrata empregados, como o produtor rural.
+
+- Layout: 14 dígitos impressos como `000.000.000/000-00`: a base de 9 dígitos do CPF do titular, um número de ordem de 3 dígitos e 2 dígitos verificadores.
+- Os dois dígitos verificadores seguem o módulo 11 do CNPJ; o par é então somado a 12, com retorno a zero acima de 99.
```javascript
import { isValidCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1902,9 +2294,13 @@ isValidCaepf('00000000000000'); // false (dígitos da base repetidos)
isValidCaepf('00000000000012'); // false (dígitos da base repetidos)
```
+Fonte: [ghiorzi.org](http://ghiorzi.org/DVnew.htm) e [brazilian-values](https://github.com/VitorLuizC/brazilian-values/blob/master/src/validators/isCAEPF.ts).
+
### formatCaepf
-Formata um número de CAEPF (Cadastro de Atividade Econômica da Pessoa Física) na máscara usual `000.000.000/000-00`, a mesma em que as fontes da regra do dígito verificador concordam (a Receita Federal não a publica). Formata progressivamente, até onde os dígitos informados alcançarem, então também pode ser usada como máscara de digitação. `options.pad` (parte de `FormatCaepfOptions`) preenche à esquerda com zeros até 14 dígitos (padrão `false`).
+Formata um número de CAEPF (Cadastro de Atividade Econômica da Pessoa Física) na máscara usual `000.000.000/000-00`.
+
+- Mesmas regras de `formatCei`, com `pad` (`FormatCaepfOptions`) completando até 14 dígitos (padrão `false`).
```javascript
import { formatCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1916,7 +2312,7 @@ formatCaepf('184', { pad: true }); // 000.000.000/001-84
### parseCaepf
-Remove a formatação do CAEPF (Cadastro de Atividade Econômica da Pessoa Física), mantém apenas os dígitos e limita o resultado a 14 dígitos. Um valor mais curto passa adiante até onde vai; use `isValidCaepf` para verificar o número em si.
+Remove a formatação do CAEPF (Cadastro de Atividade Econômica da Pessoa Física), mantém apenas os dígitos e limita o resultado a 14 dígitos.
```javascript
import { parseCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1928,7 +2324,11 @@ parseCaepf('293.118.610/001-84'); // '29311861000184'
### isValidCbo
-Valida se um código CBO (Classificação Brasileira de Ocupações) existe na tabela de ocupações do MTE. Aceita o código com ou sem a máscara de hífen, ou como número. Uma string só é lida como código quando está escrita em uma dessas formas (os 6 dígitos, ou a máscara `NNNN-NN`, com um único separador entre os grupos e espaços em branco opcionais no início e no fim), e um número só quando é um inteiro seguro não negativo. Um código CBO sempre tem 6 dígitos e os zeros à esquerda fazem parte dele, então um valor escrito apenas com dígitos é completado com zeros à esquerda até 6, seja ele string ou número, exatamente como `getBankByCode` completa um código de banco: `10205`, `'10205'` e `'010205'` são o mesmo código. Um valor mascarado já carrega os seus separadores e é lido como foi escrito.
+Valida um código CBO (Classificação Brasileira de Ocupações) contra a tabela oficial da CBO 2002.
+
+- Aceita uma string com os 6 dígitos ou com a máscara `NNNN-NN`, ou um número.
+- Uma string mascarada precisa de um único separador (espaço, `.`, `-` ou `/`) entre os grupos. Qualquer outra string é rejeitada, em vez de ter seus dígitos extraídos.
+- Dígitos sem máscara são completados com zeros à esquerda até 6, como string ou como número. Um valor mascarado é lido como foi escrito.
```javascript
import { isValidCbo } from '@brazilian-utils/brazilian-utils';
@@ -1943,11 +2343,13 @@ isValidCbo('2124abc05'); // false (não é uma forma documentada)
isValidCbo(-212405); // false (não é um inteiro seguro não negativo)
```
-Os títulos das ocupações vêm da [tabela oficial de ocupações da CBO 2002 publicada pelo MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
+Fonte: [tabela de ocupações da CBO 2002 publicada pelo MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
### parseCbo
-Remove a formatação do CBO (Classificação Brasileira de Ocupações), mantém apenas os dígitos e limita o resultado a 6 dígitos. Um valor mais curto passa adiante até onde vai e nada é preenchido com zeros à esquerda aqui, então o zero inicial de um código como `010205` precisa ser escrito; use `getCbo` ou `isValidCbo`, que preenchem um código numérico sem máscara, para consultar uma ocupação.
+Remove a formatação do CBO (Classificação Brasileira de Ocupações), mantém apenas os dígitos e limita o resultado a 6 dígitos.
+
+- Nada é completado com zeros à esquerda: o zero inicial de um código como `010205` precisa ser escrito. Use `getCbo` ou `isValidCbo` para consultar uma ocupação.
```javascript
import { parseCbo } from '@brazilian-utils/brazilian-utils';
@@ -1957,7 +2359,9 @@ parseCbo('2124-05'); // '212405'
### getCbo
-Consulta um código CBO (Classificação Brasileira de Ocupações) e retorna o título oficial da ocupação, no registro `{ code, description }` que toda consulta desta biblioteca devolve. Um valor escrito apenas com dígitos mantém os zeros à esquerda implícitos, tanto como string quanto como número: `getCbo(10205)` e `getCbo('10205')` são lidos como `010205`. Valem as mesmas regras de entrada de `isValidCbo`: uma string precisa estar escrita com os 6 dígitos ou com a máscara `NNNN-NN`, e um número precisa ser um inteiro seguro não negativo.
+Consulta um código CBO (Classificação Brasileira de Ocupações) e retorna o título oficial da ocupação. O resultado é um registro `Cbo`: `{ code, description }`.
+
+- Mesmas regras de `isValidCbo`. Retorna `null` quando o código é desconhecido ou o valor não está em uma forma documentada.
```javascript
import { getCbo } from '@brazilian-utils/brazilian-utils';
@@ -1969,11 +2373,13 @@ getCbo('000000'); // null
getCbo('2124abc05'); // null (não é uma forma documentada)
```
-Os títulos das ocupações vêm da [tabela oficial de ocupações da CBO 2002 publicada pelo MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
+Fonte: [tabela de ocupações da CBO 2002 publicada pelo MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
### isValidCnae
-Valida se um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas) existe na [tabela CNAE-Subclasses 2.3 publicada pelo IBGE](https://concla.ibge.gov.br/busca-online-cnae.html), a revisão de subclasses atual da CNAE 2.0. Aceita o código com ou sem a máscara `NNNN-N/NN`, ou como número. Uma string só é lida como código quando está escrita em uma dessas formas (os 7 dígitos, ou a máscara, com um único separador entre os grupos e espaços em branco opcionais no início e no fim), e um número só quando é um inteiro seguro não negativo. Um código de subclasse CNAE sempre tem 7 dígitos e os zeros à esquerda fazem parte dele, então um valor escrito apenas com dígitos é completado com zeros à esquerda até 7, seja ele string ou número: `111301`, `'111301'` e `'0111301'` são o mesmo código. Um valor mascarado já carrega os seus separadores e é lido como foi escrito.
+Valida um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas) contra a tabela CNAE-Subclasses 2.3, a revisão de subclasses atual da CNAE 2.0.
+
+- Mesmas regras de `isValidCbo`, com 7 dígitos e a máscara `NNNN-N/NN`.
```javascript
import { isValidCnae } from '@brazilian-utils/brazilian-utils';
@@ -1987,9 +2393,14 @@ isValidCnae('0111abc301'); // false (não é uma forma documentada)
isValidCnae(-111301); // false (não é um inteiro seguro não negativo)
```
+Fonte: [CNAE-Subclasses 2.3 na CONCLA/IBGE](https://concla.ibge.gov.br/busca-online-cnae.html) e a [API de subclasses do IBGE](https://servicodados.ibge.gov.br/api/v2/cnae/subclasses).
+
### formatCnae
-Formata um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas). `options.pad` (parte de `FormatCnaeOptions`) funciona exatamente como em `formatCpf`/`formatCep`: com o padrão `false` a máscara é aplicada progressivamente, até onde o valor vai, que é o que um campo sendo digitado precisa; com `true` o valor é primeiro completado com zeros à esquerda até os 7 dígitos de uma subclasse completa, então ele sempre volta com a máscara inteira. Um número é tratado exatamente como a string dos seus dígitos, ou seja, só é completado com `pad: true`. Como todo formatador deste pacote, o valor é lido pelos seus dígitos e a máscara é aplicada até onde eles vão: caracteres fora da máscara são descartados e um número é lido como a string dos seus dígitos, sinal e ponto decimal inclusos. Use `isValidCnae` para verificar um código.
+Formata um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas). Só a estrutura muda; use `isValidCnae` para conferir um código com a tabela.
+
+- **Opções** (`FormatCnaeOptions`): `pad` (padrão `false`) completa antes o valor com zeros à esquerda até os 7 dígitos de um código completo. Sem ele a máscara é aplicada até onde o valor vai.
+- Caracteres fora da máscara são descartados, e um número é lido como a string dos seus dígitos. Retorna `''` quando não há dígito algum.
```javascript
import { formatCnae } from '@brazilian-utils/brazilian-utils';
@@ -2005,18 +2416,23 @@ formatCnae(-6201501); // 6201-5/01
### parseCnae
-Remove a formatação do CNAE (Classificação Nacional de Atividades Econômicas), mantém apenas os dígitos e limita o resultado aos 7 dígitos de um código de subclasse completo. Nada é preenchido com zeros à esquerda aqui; use `getCnae` ou `isValidCnae`, que preenchem um código numérico sem máscara, para consultar uma subclasse.
+Remove a formatação do CNAE (Classificação Nacional de Atividades Econômicas), mantém apenas os dígitos e limita o resultado aos 7 dígitos de um código de subclasse completo.
+
+- Mesmas regras de `parseCbo`: nada é completado com zeros à esquerda aqui.
```javascript
import { parseCnae } from '@brazilian-utils/brazilian-utils';
parseCnae('6201-5/01'); // '6201501'
-parseCnae('62'); // '62' (a partial code is kept as written)
+parseCnae('62'); // '62' (um código parcial é mantido como está)
```
### getCnae
-Busca um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas) e retorna seu código e a descrição oficial. O `code` volta com os 7 dígitos crus, como em toda consulta desta biblioteca; passe-o para `formatCnae` para obter a forma `NNNN-N/NN`. Um valor escrito apenas com dígitos mantém os zeros à esquerda implícitos, tanto como string quanto como número: `getCnae(111301)` e `getCnae('111301')` são lidos como `0111301`. Valem as mesmas regras de entrada de `isValidCnae`: uma string precisa estar escrita com os 7 dígitos ou com a máscara `NNNN-N/NN`, e um número precisa ser um inteiro seguro não negativo.
+Consulta um código de subclasse CNAE (Classificação Nacional de Atividades Econômicas) e retorna seu código e a descrição oficial. O resultado é um registro `Cnae`: `{ code, description }`.
+
+- Mesmas regras de `getCbo`, com 7 dígitos e a máscara `NNNN-N/NN`.
+- `code` retorna com os 7 dígitos sem máscara; passe-o para `formatCnae` para obter a forma `NNNN-N/NN`.
```javascript
import { formatCnae, getCnae } from '@brazilian-utils/brazilian-utils';
@@ -2029,9 +2445,13 @@ getCnae('0111abc301'); // null (não é uma forma documentada)
formatCnae(getCnae('6201501')?.code); // 6201-5/01 (aplicar a máscara é trabalho do formatador)
```
+Fonte: [CNAE-Subclasses 2.3 na CONCLA/IBGE](https://concla.ibge.gov.br/busca-online-cnae.html) e a [API de subclasses do IBGE](https://servicodados.ibge.gov.br/api/v2/cnae/subclasses).
+
### isValidNcm
-Valida se um código NCM (Nomenclatura Comum do Mercosul) existe na tabela vigente publicada pelo Siscomex/MDIC. Aceita o código com ou sem a máscara de pontos, ou como número. Uma string só é lida como código quando está escrita em uma dessas formas (os 8 dígitos, ou a máscara `NNNN.NN.NN`, com um único separador entre os grupos e espaços em branco opcionais no início e no fim), e um número só quando é um inteiro seguro não negativo. Um código NCM sempre tem 8 dígitos e os zeros à esquerda fazem parte dele, então um valor escrito apenas com dígitos é completado com zeros à esquerda até 8, seja ele string ou número: `1012100`, `'1012100'` e `'01012100'` são o mesmo código. Um valor mascarado já carrega os seus separadores e é lido como foi escrito.
+Valida um código NCM (Nomenclatura Comum do Mercosul) contra a tabela vigente publicada pelo Siscomex/MDIC.
+
+- Mesmas regras de `isValidCbo`, com 8 dígitos e a máscara `NNNN.NN.NN`.
```javascript
import { isValidNcm } from '@brazilian-utils/brazilian-utils';
@@ -2045,9 +2465,14 @@ isValidNcm('abc01012100'); // false (não é uma forma documentada)
isValidNcm(-84713012); // false (não é um inteiro seguro não negativo)
```
+Fonte: [nomenclatura NCM publicada pelo Portal Único Siscomex](https://portalunico.siscomex.gov.br/classif/api/publico/nomenclatura/download/json).
+
### formatNcm
-Formata um código NCM (Nomenclatura Comum do Mercosul). `options.pad` (parte de `FormatNcmOptions`) funciona exatamente como em `formatCpf`/`formatCep`: com o padrão `false` a máscara é aplicada progressivamente, até onde o valor vai, que é o que um campo sendo digitado precisa; com `true` o valor é primeiro completado com zeros à esquerda até os 8 dígitos de um código completo, então ele sempre volta com a máscara inteira. Um número é tratado exatamente como a string dos seus dígitos, ou seja, só é completado com `pad: true`. Como todo formatador deste pacote, o valor é lido pelos seus dígitos e a máscara é aplicada até onde eles vão: caracteres fora da máscara são descartados e um número é lido como a string dos seus dígitos, sinal e ponto decimal inclusos. Use `isValidNcm` para verificar um código.
+Formata um código NCM (Nomenclatura Comum do Mercosul). Só a estrutura muda; use `isValidNcm` para conferir um código com a tabela.
+
+- **Opções** (`FormatNcmOptions`): `pad` (padrão `false`) completa antes o valor com zeros à esquerda até os 8 dígitos de um código completo.
+- Mesmas regras de `formatCnae`, com a máscara `NNNN.NN.NN`.
```javascript
import { formatNcm } from '@brazilian-utils/brazilian-utils';
@@ -2062,20 +2487,24 @@ formatNcm(-84713012); // 8471.30.12
### parseNcm
-Remove a formatação do NCM (Nomenclatura Comum do Mercosul), mantém apenas os dígitos e limita o resultado aos 8 dígitos de um código completo. Nada é preenchido com zeros à esquerda aqui; use `isValidNcm`, que preenche um código numérico sem máscara, para verificar um código na tabela oficial.
+Remove a formatação do NCM (Nomenclatura Comum do Mercosul), mantém apenas os dígitos e limita o resultado aos 8 dígitos de um código completo.
+
+- Mesmas regras de `parseCbo`: nada é completado com zeros à esquerda aqui.
```javascript
import { parseNcm } from '@brazilian-utils/brazilian-utils';
parseNcm('8471.30.12'); // '84713012'
-parseNcm('8471'); // '8471' (a partial code is kept as written)
+parseNcm('8471'); // '8471' (um código parcial é mantido como está)
```
### isValidCfop
-Valida se um código CFOP (Código Fiscal de Operações e Prestações) existe na tabela oficial. A tabela é o [Anexo II consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), o texto vigente (redação atual dada pelo Ajuste SINIEF 03/24, última alteração pelo [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25)), e não o texto congelado de 2001 do Ajuste SINIEF 07/01. Só os códigos operáveis contam: os títulos de grupo e subgrupo da nomenclatura oficial, os códigos terminados em `00` e `50` (1000, 1100, 1150, 5350, ...), são títulos de seção e não códigos que um documento pode carregar, então são rejeitados.
+Valida um código CFOP (Código Fiscal de Operações e Prestações) contra a tabela oficial, o Anexo II consolidado do Convênio SINIEF s/nº 1970 em vigor.
-Uma string só é lida como código quando está escrita em uma das formas documentadas (os 4 dígitos, ou a forma `N.NNN` impressa no anexo, com um único separador entre os grupos e espaços em branco opcionais no início e no fim), e um número só quando é um inteiro seguro não negativo. Nenhum código CFOP começa com zero, o seu primeiro dígito é o grupo da operação (1 a 7), então aqui nada é completado: um número e a string dos mesmos dígitos são lidos de forma idêntica.
+- Só os códigos operáveis contam: os títulos de grupo e subgrupo, os códigos terminados em `00` e `50`, são rejeitados.
+- Aceita uma string com os 4 dígitos ou com a forma `N.NNN`, com um único separador (espaço, `.`, `-` ou `/`), ou um número. Qualquer outra string é rejeitada.
+- Nenhum código CFOP começa com zero, então nada é completado.
```javascript
import { isValidCfop } from '@brazilian-utils/brazilian-utils';
@@ -2089,9 +2518,13 @@ isValidCfop('abc5102'); // false (não é uma forma documentada)
isValidCfop(-5102); // false (não é um inteiro seguro não negativo)
```
+Fonte: [Anexo II consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), última alteração pelo [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25).
+
### parseCfop
-Remove a formatação do CFOP (Código Fiscal de Operações e Prestações), mantém apenas os dígitos e limita o resultado a 4 dígitos. Um valor mais curto passa adiante até onde vai. Nenhum código CFOP começa com zero, o primeiro dígito é o grupo da operação, de 1 a 7, então nada é preenchido com zeros aqui.
+Remove a formatação do CFOP (Código Fiscal de Operações e Prestações), mantém apenas os dígitos e limita o resultado a 4 dígitos.
+
+- Nenhum código CFOP começa com zero, então nada é completado aqui.
```javascript
import { parseCfop } from '@brazilian-utils/brazilian-utils';
@@ -2101,7 +2534,9 @@ parseCfop('5.102'); // '5102'
### getCfop
-Busca um código CFOP (Código Fiscal de Operações e Prestações) e retorna seu código e a descrição oficial, na redação do [Anexo II consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), no texto vigente, com última alteração pelo [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25). Os títulos de grupo e subgrupo da nomenclatura oficial, os códigos terminados em `00` e `50`, não estão na tabela e retornam `null`. Valem as mesmas regras de entrada de `isValidCfop`.
+Consulta um código CFOP (Código Fiscal de Operações e Prestações) e retorna seu código e a descrição oficial. O resultado é um registro `Cfop`: `{ code, description }`.
+
+- Mesmas regras de `isValidCfop`. Retorna `null` para um título, um código desconhecido ou um valor fora das formas documentadas.
```javascript
import { getCfop } from '@brazilian-utils/brazilian-utils';
@@ -2113,6 +2548,8 @@ getCfop('5350'); // null (título de subgrupo, não é um código operável)
getCfop('abc5102'); // null (não é uma forma documentada)
```
+Fonte: [Anexo II consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), última alteração pelo [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25).
+
### isValidCst
Valida um código de CST (Código de Situação Tributária) para um tributo. Informe o tributo em `options.tax`:
@@ -2124,13 +2561,9 @@ Valida um código de CST (Código de Situação Tributária) para um tributo. In
| `pis` | 2 dígitos | `01`-`09`, `49`, `50`-`56`, `60`-`67`, `70`-`75`, `98`, `99` |
| `cofins` | 2 dígitos | mesma tabela do `pis` |
-`options.tax` (parte de `IsValidCstOptions`) é opcional: omita-o para aceitar um código que exista em qualquer uma das quatro tabelas acima. Um `tax` fora desses quatro valores cai nesse mesmo padrão em tempo de execução, do jeito que toda outra opção escalar desta biblioteca trata um valor que não conhece.
-
-A Tabela B do ICMS é a vigente: o [Anexo I consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70), cuja redação atual veio do [Ajuste SINIEF 39/23](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2023/ajuste-sinief-39-23) (efeitos a partir de 01.12.23) e que o [Ajuste SINIEF 20/24](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2024/AJ020_24) alterou suprimindo os itens 12, 13, 52, 72 e 74 (efeitos a partir de 09.07.24) antes que eles chegassem a produzir efeitos: o 39/23 havia adiado a produção de efeitos deles para 1º de outubro de 2024, então a revogação os alcançou antes e esses códigos nunca estiveram em vigor. `02`, `15`, `53` e `61` são seus códigos de monofasia de combustíveis.
-
-Uma string só é lida como código quando está escrita em uma das formas documentadas (os 2 dígitos de um código da Tabela B, ou os 3 dígitos da forma do ICMS com um único separador opcional depois do dígito de origem, além de espaços em branco opcionais no início e no fim), e um número só quando é um inteiro seguro não negativo. O dígito de origem é a única fronteira que um CST impresso tem, então `'0 10'` e `'1-10'` são lidos, mas `'0-0'`, `'11-0'` e `'00-'` não.
-
-Um único dígito é mais estreito que qualquer uma das formas documentadas, então ele é completado com zeros à esquerda até os 3 dígitos da forma do ICMS, seja ele string ou número: `0`, `'0'` e `'000'` são todos o código ICMS `000`. Um valor de 2 dígitos já é uma forma documentada, um código da Tabela B, e é lido como foi escrito, ou seja, um código da Tabela B mantém os seus dois dígitos: `'07'`, não `7`, que é o código ICMS `007`.
+- **Opções** (`IsValidCstOptions`): `tax` escolhe a tabela. Omitido, ou fora desses quatro valores, todas as tabelas são aceitas.
+- Aceita uma string com os 2 dígitos de um código da Tabela B ou os 3 dígitos da forma do ICMS, ou um número. A forma do ICMS pode ter um único separador (espaço, `.`, `-` ou `/`) depois do dígito de origem.
+- Um único dígito é completado até a forma de 3 dígitos do ICMS; uma string de 2 dígitos é um código da Tabela B, enquanto o número `7` é o código ICMS `007`.
```javascript
import { isValidCst } from '@brazilian-utils/brazilian-utils';
@@ -2149,30 +2582,36 @@ isValidCst('abc110'); // false (não é uma forma documentada)
isValidCst(-110); // false (não é um inteiro seguro não negativo)
```
+Fonte: Tabela B do ICMS do [Anexo I do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70) alterado pelo [Ajuste SINIEF 20/24](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2024/AJ020_24); IPI, PIS e COFINS da [IN RFB nº 1.009/2010](https://normas.receita.fazenda.gov.br/sijut2consulta/link.action?idAto=15974).
+
### isValidCsosn
-Valida se um código de CSOSN (Código de Situação da Operação no Simples Nacional) é um dos 10 códigos do [Anexo III-A consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70), a tabela instituída pelo Ajuste SINIEF 03/2010: `101`, `102`, `103`, `201`, `202`, `203`, `300`, `400`, `500` ou `900`.
+Valida um código de CSOSN (Código de Situação da Operação no Simples Nacional) como um dos 10 códigos da tabela oficial: `101`, `102`, `103`, `201`, `202`, `203`, `300`, `400`, `500` ou `900`.
-Uma string só é lida como código quando está escrita como os 3 dígitos puros, com espaços em branco opcionais no início e no fim: um CSOSN não tem agrupamento impresso (a NF-e leva o dígito de origem no seu próprio campo `orig`), então `'1-01'` é rejeitado; um número só é lido quando é um inteiro seguro não negativo. Nenhum código CSOSN começa com zero, a tabela vai de `101` a `900`, então aqui nada é completado: um número e a string dos mesmos dígitos são lidos de forma idêntica.
+- Aceita uma string com os 3 dígitos puros, ou um número. Um CSOSN não tem agrupamento impresso, então `'1-01'` é rejeitado.
```javascript
import { isValidCsosn } from '@brazilian-utils/brazilian-utils';
isValidCsosn('101'); // true
+isValidCsosn(900); // true
isValidCsosn('999'); // false
isValidCsosn('abc101'); // false (não é uma forma documentada)
isValidCsosn(-101); // false (não é um inteiro seguro não negativo)
```
+Fonte: [Anexo III-A consolidado do Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70) e [Ajuste SINIEF 03/2010](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2010/aj_003_10).
+
## Texto
### capitalize
-Transforma a primeira letra de cada palavra em maiúscula do jeito que se escreve um nome, uma razão social ou um endereço brasileiro, sem precisar de opções. As palavras são separadas por espaço em branco, por `-` e `/`, pelo apóstrofo (`'d'oeste'` vira `'d'Oeste'`) e pela pontuação colada à palavra (`'(empresa)'` vira `'(Empresa)'`, `'bairro:centro'` vira `'Bairro:Centro'`), então `'MOGI-GUAÇU'` vira `'Mogi-Guaçu'`; os separadores ficam onde estão. Toda sequência de espaços em branco (tabs, quebras de linha, espaços repetidos) vira um único espaço, e o espaço no início e no fim é descartado. As partículas de nomes de origem estrangeira (`del`, `della`, `di`, `du`, `van`, `von`, `der`, `den`) ficam em minúsculas como as preposições do português, e a partícula elidida `d'` também, onde quer que apareça, sempre que um apóstrofo e uma palavra vierem logo depois (`'dias d'ávila'` vira `'Dias d'Ávila'`); uma letra sozinha logo depois de um apóstrofo é o possessivo do inglês e também fica em minúscula (`"bob's"` vira `"Bob's"`).
-
-`options.lowerCaseWords` tem como padrão as preposições, artigos e conjunções que permanecem em minúsculas dentro de um nome próprio (`de`, `da`, `do`, `e`, ...), e elas só ficam em minúsculas quando ligam duas palavras: uma delas que seja a primeira palavra, que encerre o valor ou que venha antes de uma pontuação é um designativo e mantém a maiúscula (`'rua a, 100'` vira `'Rua A, 100'` e `'condomínio a, quadra d, lote o'` vira `'Condomínio A, Quadra D, Lote O'`). `options.upperCaseWords` tem como padrão as designações societárias e as abreviações de documentos escritas em maiúsculas no uso brasileiro (`LTDA`, `S.A.`, `S/A`, `S.S.`, `S/S`, `ME`, `EPP`, `MEI`, `EIRELI`, `CIA`, `SCP`, `CNPJ`, `CPF`, `RG`, `CEP`, `UF`) mais os algarismos romanos que aparecem em nomes e endereços (de `II` a `XXIII`, exceto `VI`, que colide com a forma verbal "vi"). `SA` sem pontuação ficou de fora de propósito, por ser indistinguível do sobrenome "Sá" digitado sem o acento, enquanto `ME` é também o pronome "me", então só fica em maiúsculas na posição de designação, como última palavra do valor (`'fulano comércio me'` vira `'Fulano Comércio ME'`) ou logo antes de outra designação (`'fulano me epp'` vira `'Fulano ME EPP'`); em qualquer outro lugar é uma palavra comum (`'diga-me a verdade'` vira `'Diga-Me a Verdade'`, `'não-me-toque'` vira `'Não-Me-Toque'`). `S/A` e `S/S` são reconhecidos mesmo com a barra no meio, embora a barra separe palavras. Uma palavra de duas letras logo depois de uma `/` vira maiúscula quando é a sigla de um estado brasileiro (`'porto alegre/rs'` vira `'Porto Alegre/RS'`); essa regra é estrutural e continua valendo mesmo com `upperCaseWords` informado, enquanto uma sigla de estado que não venha depois de uma `/` é deixada como está.
+Transforma em maiúscula a primeira letra de cada palavra, do jeito que se escreve um nome, uma razão social ou um endereço brasileiro, sem precisar de opções.
-Qualquer uma das listas informada em `options` substitui inteiramente a lista padrão correspondente, e a comparação com as duas é case-insensitive (locale pt-BR). As opções são tipadas como `CapitalizeOptions`. As demais palavras são capitalizadas letra a letra: `'İSTANBUL'` vira `'İstanbul'`, e uma primeira letra cuja maiúscula tem duas letras (`ß`, a ligadura `fi`) mantém a forma, então `'straße'` vira `'Straße'` e `'ßa'` continua `'ßa'`.
+- **Opções** (`CapitalizeOptions`): `lowerCaseWords`, palavras mantidas em minúsculas entre duas palavras, por padrão preposições e artigos como `de`, `da`, `do`, `e`; `upperCaseWords`, palavras sempre em maiúsculas, por padrão designações societárias e abreviações como `LTDA`, `S.A.`, `ME`, `CNPJ` e algarismos romanos. Uma lista substitui a padrão.
+- Palavras se separam em espaços, `-`, `/`, apóstrofos e pontuação colada; espaços repetidos viram um só.
+- Palavra minúscula que é a primeira, a última ou precede pontuação é designativo e mantém a maiúscula.
+- `ME` só vira maiúsculas como designação (última palavra ou antes de outra); `SA` sem pontos fica como está (o sobrenome Sá). Sigla de estado após `/` vira maiúsculas mesmo com `upperCaseWords` informado.
```javascript
import { capitalize } from '@brazilian-utils/brazilian-utils';
@@ -2198,13 +2637,17 @@ capitalize('joão paulo ii'); // João Paulo II
capitalize('de'); // De (uma preposição mantém a maiúscula quando é a primeira palavra)
capitalize('empresa ltda', { upperCaseWords: [] }); // Empresa Ltda (a lista informada substitui a padrão)
capitalize('josé Ama MARIA', { lowerCaseWords: ['ama'] }); // José ama Maria
-capitalize('doc inválido', { upperCaseWords: ['DOC'] }); // DOC Inválido (comparação case-insensitive)
+capitalize('doc inválido', { upperCaseWords: ['DOC'] }); // DOC Inválido (comparação sem diferenciar maiúsculas de minúsculas)
capitalize(' josé maria '); // José Maria (toda sequência de espaço em branco, tabs e quebras de linha inclusive, vira um único espaço)
```
+Fonte: [Manual de Redação da Presidência da República](https://www4.planalto.gov.br/centrodeestudos/assuntos/manual-de-redacao-da-presidencia-da-republica/manual-de-redacao.pdf).
+
### removeAccents
-Remove marcas diacríticas (acentos, tils, cedilhas) de uma string, decompondo cada caractere acentuado em sua letra base mais as marcas de combinação (Unicode NFD) e descartando essas marcas.
+Remove marcas diacríticas (acentos, tils, cedilhas) de uma string.
+
+- Toda marca de combinação (categoria geral M do Unicode) é descartada, então acentos de qualquer escrita são removidos.
```javascript
import { removeAccents } from '@brazilian-utils/brazilian-utils';
@@ -2216,30 +2659,52 @@ removeAccents('Açaí'); // 'Acai'
removeAccents(''); // ''
```
-## isValidIe
+## Inscrição estadual (IE)
+
+### isValidIe
+
+Valida uma inscrição estadual para um estado. **Descontinuada:** a forma posicional `isValidIe(stateCode, ie)` continua funcionando, mas está descontinuada; use a forma com objeto `isValidIe({ value, stateCode })`.
-Valida se a inscrição estadual de um estado é válida. A UF é case-insensitive. Regras notáveis por estado: GO aceita os prefixos `10`, `11` e `15`; PA aceita `15` e `75`-`79`; MS aceita `28` e `50`; SP tem o padrão de produtor rural `P0MMMSSSSD000`; TO usa códigos de tipo de 11 dígitos (`01`, `02`, `03`, `99`). O TO também aceita uma forma de 9 dígitos, aplicando a mesma regra módulo 11 sobre os oito primeiros dígitos; a página do SINTEGRA documenta apenas a de 11 dígitos, então essa forma é comportamento da 2.3.0 mantido por compatibilidade, e não regra publicada. Uma inscrição só de zeros é aceita em todo estado cuja fórmula publicada produz dígito verificador 0 para ela (AM, BA com 8 ou 9 dígitos, CE, ES, MG, MT, PB, PE, PI, PR, RJ, RS, SC, SE, SP e TO com 9 dígitos), diferente de `isValidCpf` e `isValidCnpj`, que rejeitam dígitos repetidos. O AM entra nessa lista apenas pelo segundo ramo da fórmula publicada: o primeiro ramo da página, `Se Soma < 11 Então Dígito = 11 - Soma`, dá 11 para a inscrição só de zeros, enquanto o ramo `resto <= 1 ⇒ 0`, o implementado aqui, dá 0. A inscrição e a UF vão juntas num único objeto, tipado como `IsValidIeParams`; a forma da 2.3.0, `isValidIe(stateCode, ie)`, continua funcionando e está deprecada.
+- Recebe um único objeto (`IsValidIeParams`): `value` é a inscrição e `stateCode` o estado ao qual ela pertence (um `StateCode`, sem diferenciar maiúsculas de minúsculas).
+- GO, PA, MS, SP, TO, DF, PE, AL e RJ têm casos especiais (prefixos ou formatos extras, ou um desvio da página do SINTEGRA); veja o JSDoc em `src/is-valid-ie` para os detalhes.
+- Uma inscrição só de zeros é aceita em todo estado cuja fórmula publicada produz dígito verificador 0 para ela: AM, CE, ES, MG, MT, PB, PE, PI, PR, RJ, RS, SC, SE e SP, mais BA com 8 ou 9 dígitos e TO com 9 dígitos.
```javascript
import { isValidIe } from '@brazilian-utils/brazilian-utils';
+isValidIe({ value: '110042490114', stateCode: 'SP' }); // true
+isValidIe({ value: 'P011004243002', stateCode: 'SP' }); // true (produtor rural)
isValidIe({ value: '0187634580933', stateCode: 'AC' }); // false
-isValidIe({ value: '109161793', stateCode: 'go' }); // true (case-insensitive)
+isValidIe({ value: '109161793', stateCode: 'go' }); // true (não diferencia maiúsculas de minúsculas)
```
-## isValidEmail
+Fonte: [páginas dos estados no SINTEGRA](http://www.sintegra.gov.br/insc_est.html) e o [roteiro de crítica da SEFAZ-GO](https://goias.gov.br/economia/roteiro-de-critica-da-inscricao-estadual-de-goias/).
-Valida se email é válido. O conjunto aceito é um subconjunto prático da definição de [endereço de e-mail válido](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) do HTML da WHATWG, e não da [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322). A parte local é limitada a letras, dígitos e `_'+-.`, e não pode começar com ponto, terminar com ponto ou apóstrofo, nem conter dois pontos seguidos. O domínio precisa ter pelo menos um ponto, e cada rótulo separado por ponto segue a produção `[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?` da WHATWG, então um rótulo não pode começar nem terminar com hífen nem passar de 63 caracteres; o rótulo final é alfabético e tem de 2 a 63 letras, então `user@example.c1` é rejeitado. Partes locais entre aspas (`"john doe"@example.com`) e literais de endereço (`john@[127.0.0.1]`) são rejeitadas.
+## E-mail
+
+### isValidEmail
+
+Valida um endereço de e-mail. Um subconjunto prático da definição do HTML da WHATWG.
+
+- Parte local: letras, dígitos e `_'+-.`, sem ponto no início ou no fim e sem dois pontos seguidos.
+- Domínio: pelo menos um ponto, rótulos de até 63 caracteres, rótulo final de 2 a 63 letras; partes locais entre aspas e literais de endereço são rejeitados.
```javascript
import { isValidEmail } from '@brazilian-utils/brazilian-utils';
isValidEmail('john.doe@hotmail.com'); // true
+isValidEmail('invalid.email'); // false
```
-## isValidCreditCard
+Fonte: [HTML da WHATWG, valid e-mail address](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) e [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322).
+
+## Cartão de crédito
-Valida se um número de cartão de pagamento é válido usando o algoritmo de Luhn ([ISO/IEC 7812-1](https://www.iso.org/standard/70484.html)). Aceita os caracteres de máscara usuais (espaço em branco, `.`, `-` e `/`, o conjunto intercambiável que `isValidCpf` e `isValidCnpj` aceitam) entre dois dígitos quaisquer e espaços ao redor do valor; qualquer outro caractere invalida o valor. Eles são aceitos entre dois dígitos quaisquer, e não em posições fixas, porque o agrupamento impresso de um PAN muda com a bandeira (4-4-4-4 para Visa e Mastercard, 4-6-5 para American Express, 4-6-4 para Diners Club), então não há um único leiaute ao qual prendê-los. Não faz detecção de bandeira (Visa, Mastercard, Amex...), consulta de faixa de emissor nem validação de validade/CVV, verifica apenas a quantidade de dígitos (12 a 19) e o dígito verificador de Luhn. Um `number` só é aceito quando é um inteiro seguro não negativo: qualquer valor acima de `Number.MAX_SAFE_INTEGER` (2^53 - 1, 16 dígitos) já chega arredondado para outro número, então passe cartões mais longos como string. Um valor cujos dígitos são todos iguais (`'0000000000000000'`) é rejeitado mesmo passando no cálculo de Luhn, do jeito que todo outro validador deste pacote rejeita um documento de dígitos repetidos (`isValidCpf('00000000000')`, `isValidCns`, `isValidCaepf`, `isValidCei`).
+### isValidCreditCard
+
+Valida um número de cartão de pagamento (crédito ou débito) com o algoritmo de Luhn. Só a quantidade de dígitos (12 a 19) e o dígito verificador de Luhn são conferidos. Não há detecção de bandeira (Visa, Mastercard, Amex...), consulta de faixa de emissor nem validação de validade/CVV.
+
+- Aceita uma string ou um número, com os caracteres de máscara (espaço em branco, `.`, `-` e `/`) em qualquer posição entre os dígitos.
```javascript
import { isValidCreditCard } from '@brazilian-utils/brazilian-utils';
@@ -2248,6 +2713,7 @@ isValidCreditCard('4111111111111111'); // true (número de teste Visa)
isValidCreditCard('5555555555554444'); // true (número de teste Mastercard)
isValidCreditCard('378282246310005'); // true (número de teste American Express)
isValidCreditCard('4111 1111 1111 1111'); // true (máscara com espaços)
+isValidCreditCard('4111 - 1111 - 1111 - 1111'); // true (uma sequência de separadores entre os dígitos)
isValidCreditCard('4111.1111/1111-1111'); // true (qualquer um dos caracteres de máscara)
isValidCreditCard('4111111111111112'); // false (dígito verificador inválido)
isValidCreditCard('0000000000000000'); // false (todos os dígitos iguais, ainda que o Luhn feche)
@@ -2255,24 +2721,42 @@ isValidCreditCard('4111a1111b1111c1111'); // false (letras entre os dígitos)
isValidCreditCard(4111111111111111111); // false (acima de 2^53 - 1, passe como string)
```
-## isValidRegistroProfissional
+Fonte: [ISO/IEC 7812-1](https://www.iso.org/standard/70484.html).
+
+## Registro profissional
-Verifica a estrutura de um número de registro/inscrição profissional. Recebe um único objeto, tipado como `IsValidRegistroProfissionalParams`, no mesmo formato do `isValidBankAccount`: `value` é o número do registro, `council` escolhe o conselho emissor (`"OAB"`, `"CRM"`, `"CRO"`, `"CRP"` ou `"CRC"`) e o `stateCode` opcional verifica a UF embutida (ignorado para `"CRP"`, cujo prefixo de 2 dígitos é um código regional, não uma UF literal). Qualquer coisa que não seja um objeto, e um objeto sem `value` ou sem `council`, é `false`. Os formatos aceitos são de 4 a 6 dígitos mais a UF para `"OAB"` e `"CRM"`, de 3 a 6 dígitos mais a UF para `"CRO"`, um código regional de 2 dígitos mais 4 a 6 dígitos para `"CRP"`, e a UF mais 6 dígitos, o tipo de registro e um dígito verificador para `"CRC"`. É apenas uma verificação estrutural: a quantidade de dígitos e a UF são validadas, mas nenhum dígito verificador é calculado, mesmo para o CRC, cujo formato inclui um. Um registro no CRC é a UF, 6 dígitos, o tipo de registro (`"O"` Originário ou `"P"` Provisório, que nada diz sobre a categoria profissional) e o dígito verificador, conforme o [Manual de Registro do Sistema CFC/CRCs](https://cfc.org.br/wp-content/uploads/2018/04/1_manual_registro.pdf) (item 1.1). Um Registro Transferido ou Secundário acrescenta `"T"` ou `"S"` e a UF do CRC de destino **depois** do dígito verificador, conforme esse mesmo item e a [Resolução CFC nº 1.707/2023](https://www1.cfc.org.br/sisweb/SRE/docs/Res_1707.pdf), art. 5º parágrafo único: os exemplos do próprio Manual são `SP-123456/O-3 T-MG`, `TO-654321/P-8 T-SC` e `PI-111222/O-5 S-AC`. As duas UFs precisam ser códigos reais, e o `stateCode` é comparado com a de origem. O código regional do CRP precisa ser um dos [24 Conselhos Regionais](https://site.cfp.org.br/cfp/sistema-conselhos/conselhos-pelo-brasil/) do sistema CFP, de CRP-01 a CRP-24. Só o formato do CRC e esses códigos regionais do CRP se apoiam em fonte publicada: a página do CFP não publica o tamanho do número de inscrição, e a OAB, o CFM e o CFO não publicam formato algum, então as faixas de dígitos aceitas para `"CRP"`, `"OAB"`, `"CRM"` e `"CRO"` são convencionais, não normativas (a busca pública da OAB/SP tem `maxlength="7"`, e o CFM documenta CRMs com prefixo `300` e sufixo `P`, nenhum deles expresso por esses formatos). O CREA não é suportado: seu formato de registro não pôde ser confirmado em uma fonte oficial e publicamente documentada após a unificação nacional de 2016 (RNP).
+### isValidRegistroProfissional
+
+Verifica a estrutura de um número de registro em conselho profissional (registro/inscrição profissional). Só a quantidade de dígitos e a UF são conferidas, nunca o dígito verificador, nem no CRC.
+
+- Recebe um objeto (`IsValidRegistroProfissionalParams`): `value`, `council` (`RegistroProfissionalCouncil`: `"OAB"`, `"CRM"`, `"CRO"`, `"CRP"` ou `"CRC"`) e `stateCode` opcional (UF esperada).
+- `"OAB"` e `"CRM"`: 4 a 6 dígitos mais a UF (`123456/SP`, `123456-SP`); `"CRO"`: 3 a 6 dígitos (`12345/SP`).
+- `"CRP"`: código regional de 2 dígitos (`01` a `24`) mais 4 a 6 dígitos (`06/12345`); `stateCode` é ignorado.
+- `"CRC"`: UF, 6 dígitos, tipo de registro (`O` ou `P`) e dígito verificador (`SP-123456/O-3`); transferência acrescenta `T` ou `S` e a UF destino (`SP-123456/O-3 T-MG`). `stateCode` confere a UF de origem.
+- Formatos de OAB, CRM, CRO e CRP são convencionais (nenhum é publicado); CREA não é coberto.
```javascript
import { isValidRegistroProfissional } from '@brazilian-utils/brazilian-utils';
isValidRegistroProfissional({ value: '123456/SP', council: 'OAB' }); // true
isValidRegistroProfissional({ value: '123456-RJ', council: 'OAB', stateCode: 'SP' }); // false (UF divergente)
+isValidRegistroProfissional({ value: '123456', council: 'OAB' }); // false (sem UF)
isValidRegistroProfissional({ value: '06/12345', council: 'CRP' }); // true
isValidRegistroProfissional({ value: 'SP-123456/O-3', council: 'CRC' }); // true
isValidRegistroProfissional({ value: 'SP-123456/O-3 T-MG', council: 'CRC' }); // true (registro transferido)
isValidRegistroProfissional({ value: 'SP-123456/T-3', council: 'CRC' }); // false ("T" não é tipo de registro)
```
-## isValidVin
+Fonte: [Manual de Registro do Sistema CFC/CRCs](https://cfc.org.br/wp-content/uploads/2018/04/1_manual_registro.pdf), [Resolução CFC nº 1.707/2023](https://www1.cfc.org.br/sisweb/SRE/docs/Res_1707.pdf), [regionais do CFP](https://site.cfp.org.br/cfp/sistema-conselhos/conselhos-pelo-brasil/).
+
+## VIN
-Valida se um VIN (Vehicle Identification Number / chassi) é válido. Verifica o tamanho (17 caracteres), as letras excluídas (`I`, `O`, `Q` nunca são válidas; estrutura da [ISO 3779:2009](https://www.iso.org/standard/52200.html)) e o dígito verificador na 9ª posição, calculado e transliterado conforme o [49 CFR 565.15](https://www.ecfr.gov/current/title-49/section-565.15). Esse dígito verificador é uma exigência norte-americana (49 CFR 565.15 / SAE J853): a [Resolução CONTRAN nº 968/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9682022.pdf) (que revogou a Resolução CONTRAN nº 24/1998 a partir de 1º de janeiro de 2025) e a ABNT NBR 6066 definem a estrutura do VIN brasileiro, mas não o exigem, então muitos VINs fabricados no Brasil não possuem um dígito verificador correspondente. Esta função é, portanto, uma verificação estrutural no padrão norte-americano, não um validador universal de VINs brasileiros. Não diferencia maiúsculas de minúsculas e remove espaços nas extremidades. Um VIN é impresso como uma sequência única de 17 caracteres, então, diferente dos documentos que este pacote mascara (`isValidCpf`, `isValidCnpj`, `isValidNfeKey`), ele não tem limite de grupo onde escrever um separador e nenhum é aceito: um espaço, `.`, `-` ou `/` entre os caracteres é rejeitado em vez de removido. Um valor cujos 17 caracteres são todos iguais (`'00000000000000000'`) é rejeitado mesmo com o dígito verificador correspondente, do jeito que todo outro validador deste pacote rejeita um documento de dígitos repetidos.
+### isValidVin
+
+Valida um VIN (Vehicle Identification Number / chassi). É uma verificação estrutural no padrão norte-americano, não um validador universal de VINs brasileiros.
+
+- Confere o tamanho de 17 caracteres, as letras excluídas `I`, `O` e `Q` e o dígito verificador na 9ª posição.
+- As normas brasileiras não exigem o dígito verificador, então muitos VINs fabricados no Brasil não passam nele.
```javascript
import { isValidVin } from '@brazilian-utils/brazilian-utils';
@@ -2282,4 +2766,7 @@ isValidVin('1m8gdm9axkp042788'); // true (dígito verificador X, minúsculo)
isValidVin('1HGCM82633A004353'); // false (dígito verificador inválido)
isValidVin('00000000000000000'); // false (todos os caracteres iguais, ainda que o dígito feche)
isValidVin('1HGCM8263IA004352'); // false (contém a letra excluída I)
+isValidVin('1HGCM82633A00435'); // false (16 caracteres)
```
+
+Fonte: [ISO 3779:2009](https://www.iso.org/standard/52200.html), [49 CFR 565.15](https://www.ecfr.gov/current/title-49/section-565.15) e [Resolução CONTRAN nº 968/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9682022.pdf).
diff --git a/docs/run.js b/docs/run.js
new file mode 100644
index 000000000..88a3915be
--- /dev/null
+++ b/docs/run.js
@@ -0,0 +1,295 @@
+/*
+ * "Run" buttons for the guide pages (docs/guides, docs/pt-br/guides).
+ *
+ * A docsify plugin: after a guide page renders, every code block that is a complete example gets a
+ * Run button: an `html` document, a `jsx`/`tsx` block with a default export (React), a `vue`
+ * single-file component, or a `typescript` block whose default export is an `@Component`
+ * (Angular). Nothing is downloaded until the button is clicked. Then the block is compiled in the
+ * page (JSX through sucrase, a single-file component through @vue/compiler-sfc, an Angular
+ * component through Babel with the TypeScript preset and legacy decorators, each loaded from the
+ * CDN on first use) and runs in a sandboxed iframe under the block, with an import map that
+ * resolves the bare imports (`react`, `vue`, `@angular/*`, `zod`, `valibot` and the package
+ * itself) to the CDN. The iframe fetches those modules only at that point.
+ *
+ * The versions are pinned to the latest releases at the time of writing; bump them here.
+ * `window.$docsify.run` overrides the URLs (`importMap`, `sucrase`, `compilerSfc`, `babel`),
+ * which is how the local test runs the examples against copies of the modules.
+ */
+(function () {
+ var CDN = 'https://cdn.jsdelivr.net/npm/';
+ var VERSIONS = {
+ react: '19.3.0',
+ vue: '3.5.43',
+ angular: '22.1.7',
+ rxjs: '7.8.2',
+ zod: '4.6.5',
+ valibot: '1.5.0',
+ sucrase: '3.35.1',
+ babel: '7.29.9',
+ };
+
+ var DEFAULTS = {
+ importMap: {
+ '@brazilian-utils/brazilian-utils': CDN + '@brazilian-utils/brazilian-utils/+esm',
+ react: CDN + 'react@' + VERSIONS.react + '/+esm',
+ 'react/jsx-runtime': CDN + 'react@' + VERSIONS.react + '/jsx-runtime/+esm',
+ 'react-dom/client': CDN + 'react-dom@' + VERSIONS.react + '/client/+esm',
+ vue: CDN + 'vue@' + VERSIONS.vue + '/dist/vue.esm-browser.prod.js',
+ '@angular/core': CDN + '@angular/core@' + VERSIONS.angular + '/+esm',
+ '@angular/common': CDN + '@angular/common@' + VERSIONS.angular + '/+esm',
+ '@angular/forms': CDN + '@angular/forms@' + VERSIONS.angular + '/+esm',
+ '@angular/platform-browser': CDN + '@angular/platform-browser@' + VERSIONS.angular + '/+esm',
+ '@angular/compiler': CDN + '@angular/compiler@' + VERSIONS.angular + '/+esm',
+ rxjs: CDN + 'rxjs@' + VERSIONS.rxjs + '/+esm',
+ 'rxjs/operators': CDN + 'rxjs@' + VERSIONS.rxjs + '/operators/+esm',
+ zod: CDN + 'zod@' + VERSIONS.zod + '/+esm',
+ valibot: CDN + 'valibot@' + VERSIONS.valibot + '/+esm',
+ },
+ sucrase: CDN + 'sucrase@' + VERSIONS.sucrase + '/+esm',
+ compilerSfc: CDN + '@vue/compiler-sfc@' + VERSIONS.vue + '/dist/compiler-sfc.esm-browser.js',
+ babel: CDN + '@babel/standalone@' + VERSIONS.babel + '/babel.min.js',
+ };
+
+ var TEXT = {
+ '/': { run: 'Run', close: 'Close', running: 'Running...', title: 'Run this example in the page' },
+ '/pt-br/': { run: 'Executar', close: 'Fechar', running: 'Executando...', title: 'Executa este exemplo na página' },
+ };
+
+ /** The base style of the sandbox, so a form reads the same in every example. */
+ var FRAME_CSS =
+ 'body{font:15px/1.5 system-ui,sans-serif;margin:0;padding:12px;color:#222;background:#fff}' +
+ 'label{display:block;margin:0 0 10px}input{display:block;width:100%;max-width:320px;box-sizing:border-box;' +
+ 'margin:4px 0;padding:6px 8px;font:inherit;border:1px solid #bbb;border-radius:4px}' +
+ 'small{display:block;color:#b00020}button{padding:6px 14px;font:inherit}pre{background:#f4f4f4;padding:8px;' +
+ 'overflow:auto}dt{font-weight:600;margin-top:8px}dd{margin:0}.run-error{color:#b00020;white-space:pre-wrap}';
+
+ /** The script every sandbox starts with: error reporting and the height of the page. */
+ var FRAME_BOOT =
+ 'window.__report=function(e){var p=document.createElement("pre");p.className="run-error";' +
+ 'p.textContent=String(e&&e.stack||e);document.body.appendChild(p)};' +
+ 'window.addEventListener("error",function(e){__report(e.error||e.message)});' +
+ 'window.addEventListener("unhandledrejection",function(e){__report(e.reason)});' +
+ 'new ResizeObserver(function(){parent.postMessage({runHeight:document.documentElement.scrollHeight},"*")})' +
+ '.observe(document.documentElement);';
+
+ var config = Object.assign({}, DEFAULTS, window.$docsify.run || {});
+ config.importMap = Object.assign({}, DEFAULTS.importMap, (window.$docsify.run || {}).importMap || {});
+
+ var loaders = {};
+
+ /** Loads an ES module from the CDN once and caches the promise. */
+ function load(url) {
+ if (!loaders[url]) loaders[url] = import(/* webpackIgnore: true */ url);
+ return loaders[url];
+ }
+
+ /** Loads a classic script (Babel standalone is one) once and resolves with the global it defines. */
+ function loadScript(url, globalName) {
+ if (!loaders[url]) {
+ loaders[url] = new Promise(function (resolve, reject) {
+ if (window[globalName]) return resolve(window[globalName]);
+ var script = document.createElement('script');
+ script.src = url;
+ script.onload = function () { resolve(window[globalName]); };
+ script.onerror = function () { reject(new Error('Could not load ' + url)); };
+ document.head.appendChild(script);
+ });
+ }
+ return loaders[url];
+ }
+
+ function escapeScript(code) {
+ return code.replace(/<\/script/gi, '<\\/script');
+ }
+
+ function moduleUrl(code) {
+ return 'data:text/javascript;base64,' + btoa(unescape(encodeURIComponent(code)));
+ }
+
+ function importMapTag(imports) {
+ return '';
+ }
+
+ function document_(body, head) {
+ return ' ' + (head || '') + '' +
+ '' + body + '';
+ }
+
+ /** Wraps the boot of an example: the imports it needs and the user's module, mounted on the page. */
+ function bootDocument(mount, boot, head) {
+ return document_(mount + '', importMapTag(config.importMap) + (head || ''));
+ }
+
+ /** A React example: JSX compiled by sucrase, the default export mounted on #app. */
+ function reactDocument(code) {
+ return load(config.sucrase).then(function (sucrase) {
+ var js = sucrase.transform(code, { transforms: ['jsx', 'typescript'], jsxRuntime: 'automatic', production: true }).code;
+ return bootDocument(
+ '
',
+ 'const [{ createElement }, { createRoot }, mod] = await Promise.all([import("react"), import("react-dom/client"), import(' + JSON.stringify(moduleUrl(js)) + ')]);' +
+ 'createRoot(document.getElementById("app")).render(createElement(mod.default));'
+ );
+ });
+ }
+
+ /** A Vue example: the single-file component compiled by @vue/compiler-sfc and mounted on #app. */
+ function vueDocument(code) {
+ return load(config.compilerSfc).then(function (sfc) {
+ var parsed = sfc.parse(code, { filename: 'Example.vue' });
+ if (parsed.errors.length) throw parsed.errors[0];
+ var descriptor = parsed.descriptor;
+ var id = 'example';
+ var js;
+ if (descriptor.scriptSetup) {
+ // ';
+ if (/]*>/i.test(html)) return Promise.resolve(html.replace(/]*>/i, function (head) { return head + map + boot; }));
+ if (/]*>/i.test(html)) return Promise.resolve(html.replace(/]*>/i, function (body) { return map + boot + body; }));
+ return Promise.resolve(document_(html, map));
+ }
+
+ function kindOf(pre, code) {
+ var lang = pre.getAttribute('data-lang') || '';
+ if (lang === 'html') return /]/i.test(code) ? 'html' : null;
+ if (lang === 'jsx' || lang === 'tsx') return /export default/.test(code) ? 'react' : null;
+ if (lang === 'vue') return /]/i.test(code) ? 'vue' : null;
+ if (lang === 'typescript' || lang === 'ts') return /@Component\(/.test(code) && /export default/.test(code) ? 'angular' : null;
+ return null;
+ }
+
+ var COMPILERS = { html: htmlDocument, react: reactDocument, vue: vueDocument, angular: angularDocument };
+
+ function addButton(pre, text) {
+ var code = pre.querySelector('code');
+ if (!code || pre.querySelector('.run-button')) return;
+ var source = code.textContent;
+ var kind = kindOf(pre, source);
+ if (!kind) return;
+
+ var button = document.createElement('button');
+ button.type = 'button';
+ button.className = 'run-button';
+ button.textContent = text.run;
+ button.title = text.title;
+ pre.appendChild(button);
+
+ var wrapper = null;
+
+ function open(node) {
+ wrapper = document.createElement('div');
+ wrapper.className = 'run-output';
+ wrapper.appendChild(node);
+ pre.parentNode.insertBefore(wrapper, pre.nextSibling);
+ button.textContent = text.close;
+ button.disabled = false;
+ }
+
+ function close() {
+ if (wrapper) wrapper.remove();
+ wrapper = null;
+ button.textContent = text.run;
+ button.disabled = false;
+ }
+
+ button.addEventListener('click', function () {
+ if (wrapper) return close();
+ button.disabled = true;
+ button.textContent = text.running;
+ COMPILERS[kind](source).then(function (html) {
+ var frame = document.createElement('iframe');
+ frame.setAttribute('sandbox', 'allow-scripts allow-forms');
+ frame.setAttribute('title', text.run);
+ frame.srcdoc = html;
+ open(frame);
+ window.addEventListener('message', function onMessage(event) {
+ if (!frame.isConnected) return window.removeEventListener('message', onMessage);
+ if (event.source !== frame.contentWindow || !event.data || !event.data.runHeight) return;
+ frame.style.height = Math.min(Math.max(event.data.runHeight + 4, 80), 800) + 'px';
+ });
+ }, function (error) {
+ var message = document.createElement('pre');
+ message.className = 'run-error';
+ message.textContent = String(error && error.message || error);
+ open(message);
+ });
+ });
+ }
+
+ var STYLE =
+ '.markdown-section pre .run-button{position:absolute;right:0;bottom:0;z-index:1;border:0;border-radius:4px 0 0 0;' +
+ 'background:var(--theme-color,#009739);color:#fff;font:inherit;font-size:.85em;padding:.4em .9em;cursor:pointer;opacity:.85}' +
+ '.markdown-section pre .run-button:hover,.markdown-section pre .run-button:focus{opacity:1}' +
+ '.markdown-section pre .run-button:disabled{opacity:.6;cursor:wait}' +
+ '.markdown-section .run-output{margin:-16px 0 24px;border:1px solid var(--border-color,#ddd);border-top:0;border-radius:0 0 4px 4px}' +
+ '.markdown-section .run-output iframe{display:block;width:100%;height:120px;border:0;background:#fff}' +
+ '.markdown-section .run-output .run-error{margin:0;color:#b00020;white-space:pre-wrap}';
+
+ window.$docsify = window.$docsify || {};
+ window.$docsify.plugins = (window.$docsify.plugins || []).concat(function (hook, vm) {
+ hook.mounted(function () {
+ var style = document.createElement('style');
+ style.textContent = STYLE;
+ document.head.appendChild(style);
+ });
+ hook.doneEach(function () {
+ var path = vm.route.path || '';
+ if (path.indexOf('/guides/') === -1) return;
+ var text = TEXT[path.indexOf('/pt-br/') === 0 ? '/pt-br/' : '/'];
+ var blocks = document.querySelectorAll('.markdown-section pre[data-lang]');
+ for (var i = 0; i < blocks.length; i++) addButton(blocks[i], text);
+ });
+ });
+})();
diff --git a/docs/sitemap.xml b/docs/sitemap.xml
index 30e9345a5..8ede56e42 100644
--- a/docs/sitemap.xml
+++ b/docs/sitemap.xml
@@ -17,6 +17,30 @@
+
+ https://brazilian-utils.com.br/guides/react
+
+
+
+
+
+ https://brazilian-utils.com.br/guides/vue
+
+
+
+
+
+ https://brazilian-utils.com.br/guides/angular
+
+
+
+
+
+ https://brazilian-utils.com.br/guides/vanilla
+
+
+
+
https://brazilian-utils.com.br/migration-v1-to-v2
@@ -35,6 +59,30 @@
+
+ https://brazilian-utils.com.br/pt-br/guides/react
+
+
+
+
+
+ https://brazilian-utils.com.br/pt-br/guides/vue
+
+
+
+
+
+ https://brazilian-utils.com.br/pt-br/guides/angular
+
+
+
+
+
+ https://brazilian-utils.com.br/pt-br/guides/vanilla
+
+
+
+
https://brazilian-utils.com.br/pt-br/migration-v1-to-v2
diff --git a/docs/utilities.html b/docs/utilities.html
index 987fe725b..541f32af5 100644
--- a/docs/utilities.html
+++ b/docs/utilities.html
@@ -50,14 +50,14 @@
"@id": "https://brazilian-utils.com.br/#website",
"url": "https://brazilian-utils.com.br/",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"inLanguage": ["en", "pt-BR"]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://brazilian-utils.com.br/#library",
"name": "Brazilian Utils",
- "description": "Zero-dependency, tree-shakeable utils for Brazilian-specific businesses: CPF, CNPJ, boleto, Pix, CEP, holidays and more.",
+ "description": "Zero-dependency, tree-shakeable utilities for Brazilian data: validate, format, parse and generate CPF, CNPJ, CEP, boleto, Pix, holidays and more.",
"url": "https://brazilian-utils.com.br/",
"codeRepository": "https://github.com/brazilian-utils/javascript",
"programmingLanguage": "TypeScript",
@@ -258,8 +258,19 @@
};
+
+
+
+
+
+
+
diff --git a/docs/utilities.md b/docs/utilities.md
index a4b07b62a..d6fab3595 100644
--- a/docs/utilities.md
+++ b/docs/utilities.md
@@ -4,13 +4,27 @@ description: "Every utility of Brazilian Utils, grouped by family (CPF, CNPJ, CE
keywords: ["CPF", "CNPJ", "CEP", "boleto", "Pix", "NF-e", "phone", "license plate", "RENAVAM", "PIS", "CNH", "IBAN", "holidays", "business days", "CBO", "CNAE", "NCM", "CFOP", "validator", "formatter", "parser", "generator"]
---
-Here you will find all the utilities available for use.
+Every function of the package, grouped by family. Each section says what the function does, its options, what it returns on bad input, and shows an example.
+
+## Conventions
+
+These rules hold for every function unless its section says otherwise.
+
+- **Nothing throws on bad input** (`null`, `undefined`, the wrong type): `isValid*` return `false`, `format*` and `parse*` return `''`, single-item `get*` return `null`, list `get*` return `[]`. The only exceptions are the async `getAddressInfoByCep` and `getCepInfoByAddress`, which reject with typed errors.
+- **Validators accept the value masked or not**: the usual mask characters (`.`, `-`, `/`) and spaces between or around the groups are ignored, so there is no need to strip formatting first.
+- **Formatters mask as far as the value goes**, so they also work as input masks while the user types. `parse*` functions do the reverse and keep only the meaningful characters.
+- **Generators use `Math.random()`**, so they are fine for tests and fixtures and never for anything security-related.
+- **Getters return a new array or object on every call**, so mutating a result never affects the next call.
+- **Every function is synchronous** except `getAddressInfoByCep`, `getCepInfoByAddress` and the deprecated `getMunicipality`.
+
## CPF
### isValidCpf
-Check if CPF is valid. Accepts the usual mask characters and whitespace between/around groups.
+Check if a CPF is valid.
+
+- Returns `false` for a reserved number (all digits the same, such as `00000000000`) and for a wrong check digit.
```javascript
import { isValidCpf } from '@brazilian-utils/brazilian-utils';
@@ -21,7 +35,10 @@ isValidCpf('111 444 777 35'); // true (whitespace mask)
### formatCpf
-Format CPF. `options.pad` (part of `FormatCpfOptions`) left-pads the value with zeros up to the 11 slots of the pattern before masking (default `false`). `options.obfuscate` (same type) hides the first 3 digits and the 2 check digits (`***.456.789-**`), the gov.br / Receita Federal display convention, applied after `pad`. It is read for truthiness, the way `pad` is, so any truthy value obfuscates.
+Format a CPF.
+
+- **Options** (`FormatCpfOptions`): `pad` left-pads the value with zeros to 11 digits before masking (default `false`); `obfuscate` hides the first 3 digits and the 2 check digits.
+- `obfuscate` is applied after `pad`.
```javascript
import { formatCpf } from '@brazilian-utils/brazilian-utils';
@@ -43,7 +60,10 @@ parseCpf('746.506.880-00'); // 74650688000
### generateCpf
-Generate a valid random CPF. Uses `Math.random()` internally, so it is not cryptographically secure. The optional `state` argument (typed as `StateCode`, the two-letter codes of the 27 Brazilian states, e.g. `"SP"`, `"MG"`) ties the CPF to a state by fixing the região fiscal digit in the 9th position to that state's code. Omitted, a random region is used. An unknown code draws a random região fiscal digit instead of throwing, so the result is still a valid CPF.
+Generate a valid random CPF.
+
+- The optional `state` argument (`StateCode`, e.g. `"SP"`) fixes the região fiscal digit (the 9th) to that state's code.
+- Without `state`, or with an unknown code, a random região fiscal digit is drawn.
```javascript
import { generateCpf } from '@brazilian-utils/brazilian-utils'
@@ -53,11 +73,16 @@ generateCpf('SP'); // the 9th digit is 8, the SP região fiscal code
generateCpf('MG'); // the 9th digit is 6, the MG região fiscal code
```
+Source: [Receita Federal, "Cadastros: CPF e CNPJ"](https://www.gov.br/receitafederal/pt-br/assuntos/educacao-fiscal/educacao_fiscal/folhetos-orientativos/cadastros-dig.pdf).
+
## CNPJ
### isValidCnpj
-Check if CNPJ is valid. `options.version` (part of `IsValidCnpjOptions`) picks which format is accepted: `1` (default) the numeric-only format, `2` both the numeric and the alphanumeric one; any other value is read as `1`, the way `formatCnpj` and `parseCnpj` read it. The usual mask characters and whitespace are accepted in either version. Version `2` has no reserved-value list, because the Receita Federal manual defines none for the alphanumeric format: a repeated-character alphanumeric base (all `A`s, say) that passes the checksum is accepted, while the numeric reserved numbers are rejected under version `1`.
+Check if a CNPJ is valid.
+
+- **Options** (`IsValidCnpjOptions`): `version` picks the accepted format: `1` (default) numeric only, `2` numeric and alphanumeric. Any other value is read as `1`.
+- A reserved number (all digits the same) is rejected under both versions; version `2` has no reserved list for letters.
```javascript
import { isValidCnpj } from '@brazilian-utils/brazilian-utils';
@@ -66,9 +91,15 @@ isValidCnpj('15515147234255'); // false
isValidCnpj('q0slfmbd7vx439', { version: 2 }); // true (lowercase alphanumeric)
```
+Source: [Receita Federal, Manual do DV do CNPJ](https://www.gov.br/receitafederal/pt-br/centrais-de-conteudo/publicacoes/documentos-tecnicos/cnpj/manual-dv-cnpj.pdf), [CNPJ alfanumérico](https://www.gov.br/receitafederal/pt-br/acesso-a-informacao/acoes-e-programas/programas-e-atividades/cnpj-alfanumerico).
+
### formatCnpj
-Format CNPJ. `options.pad` (part of `FormatCnpjOptions`) left-pads the value with zeros up to the 14 slots of the pattern before masking (default `false`). `options.version` (same type) picks which CNPJ format to read: `1` (default) numeric only, `2` alphanumeric. `options.obfuscate` hides the first 2 digits and the 2 check digits (`**.345.678/0001-**`), the gov.br / Receita Federal display convention. It applies to both versions and comes after `pad`, and is read for truthiness, the way `pad` is, so any truthy value obfuscates.
+Format a CNPJ.
+
+- **Options** (`FormatCnpjOptions`): `pad` left-pads the value with zeros to 14 characters before masking (default `false`); `version` picks the format, `1` (default) numeric only, `2` alphanumeric; `obfuscate` hides the first 2 digits and the 2 check digits.
+- Version `2` keeps letters (upper-cased) and digits; version `1` keeps digits only.
+- `obfuscate` works in both versions and is applied after `pad`.
```javascript
import { formatCnpj } from '@brazilian-utils/brazilian-utils';
@@ -81,7 +112,9 @@ formatCnpj('12345678000195', { obfuscate: true }); // **.345.678/0001-**
### parseCnpj
-Remove CNPJ formatting, return a normalized value, and cap the result to 14 characters. `options.version` (part of `ParseCnpjOptions`) picks which CNPJ format to normalize: `1` (default) keeps digits only, `2` keeps letters and digits, so an alphanumeric CNPJ survives the round trip.
+Remove CNPJ formatting, return a normalized value, and cap the result to 14 characters.
+
+- **Options** (`ParseCnpjOptions`): `version` picks the format: `1` (default) keeps digits only, `2` keeps letters and digits, upper-cased.
```javascript
import { parseCnpj } from '@brazilian-utils/brazilian-utils';
@@ -92,7 +125,10 @@ parseCnpj('12.OUT.345/0001-99', { version: 2 }); // 12OUT345000199
### generateCnpj
-Generate a valid random CNPJ. Uses `Math.random()` internally, so it is not cryptographically secure. The first argument is either the version, as before, or a `GenerateCnpjParams` object with the same `version` plus `branch`, the "número de ordem" (filial) block in positions 9 to 12: an integer from 1 to 9999 written zero padded to four characters, random by default. An invalid `branch` is ignored and a random block is used, and the block stays numeric on the alphanumeric version.
+Generate a valid random CNPJ.
+
+- The first argument is either the version, `1` (default) numeric or `2` alphanumeric, or a `GenerateCnpjParams` object with `version` plus `branch`.
+- `branch` is the "número de ordem" (filial) block, an integer from 1 to 9999 (random by default). An invalid `branch` is ignored. The block stays numeric in both versions.
```javascript
import { generateCnpj } from '@brazilian-utils/brazilian-utils'
@@ -107,7 +143,10 @@ generateCnpj({ version: 2, branch: 1 }); // alphanumeric CNPJ whose ordem block
### isValidCep
-Check if CEP ([brazilian postal code](https://en.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)) is valid. Accepts both `string` and `number` input, but a CEP that starts with `0` has to be passed as a string, since a number cannot keep the leading zero (`isValidCep(1310100)` is `false`, `isValidCep('01310100')` is `true`); any spaces, dots and hyphens around/between the 8 digits are ignored, but any other character, a letter in particular, makes the value invalid.
+Check if a CEP ([brazilian postal code](https://en.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)) is valid.
+
+- Accepts a `string` or a `number`. A CEP that starts with `0` has to be a string, since a number cannot keep the leading zero.
+- Spaces, dots and hyphens are ignored. Any other character makes the value invalid.
```javascript
import { isValidCep } from '@brazilian-utils/brazilian-utils';
@@ -123,7 +162,10 @@ isValidCep('12345'); // false (invalid length)
### formatCep
-Format CEP ([brazilian postal code](https://en.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)). `options.pad` (part of `FormatCepOptions`) left-pads the value with zeros to the full 8 digits before masking (default `false`); a CEP that starts with `0` given as a number loses that zero, so pass it as a string or use `pad`.
+Format a CEP ([brazilian postal code](https://en.wikipedia.org/wiki/C%C3%B3digo_de_Endere%C3%A7amento_Postal)).
+
+- **Options** (`FormatCepOptions`): `pad` left-pads the value with zeros to 8 digits before masking (default `false`).
+- A CEP that starts with `0` given as a number loses that zero: pass a string or use `pad`.
```javascript
import { formatCep } from '@brazilian-utils/brazilian-utils';
@@ -144,7 +186,7 @@ parseCep('92500-000'); // 92500000
### generateCep
-Generate a random CEP. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a random CEP. A CEP has no check digit, so every 8 digit string is structurally valid.
```javascript
import { generateCep } from '@brazilian-utils/brazilian-utils';
@@ -154,7 +196,13 @@ generateCep(); // '92500000'
### getAddressInfoByCep
-Fetch address information for a given CEP using multiple providers. Defaults to `['viacep', 'brasilapi']`. The `'widenet'` provider is deprecated (its endpoint no longer responds) and excluded from the default list, but it can still be requested explicitly via `options.providers` (typed as `CepProvider[]`). The resolved address is typed as `AddressInfo`. A transient network failure is retried twice per provider, with a 250 ms linear backoff (250 ms, then 500 ms), so a provider that keeps failing is tried up to 3 times and adds about 750 ms before its own failure lands; an HTTP error status or a non-retryable failure is not retried. The providers are started together and raced with `Promise.any`, not queried one after the other, so those retries delay nothing for the other providers, only the moment an all-failed rejection can surface. An `options.providers` that names no known provider rejects with `GetAddressInfoByCepValidationError` ("Nenhum provedor válido especificado"): an empty array, an array of unknown names, and a value that is not an array at all, `null` included. With `providers: ['brasilapi']`, a CEP BrasilAPI does not know rejects with `GetAddressInfoByCepNotFoundError`, since BrasilAPI signals a miss with HTTP 404; any other error status is still a `GetAddressInfoByCepServiceError`. All three extend `GetAddressInfoByCepError`, the base class of every error this util rejects with, so a single `catch` on it covers all of them.
+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.
+- 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.
+- All three extend `GetAddressInfoByCepError`, so one `catch` covers them.
```javascript
import { getAddressInfoByCep } from '@brazilian-utils/brazilian-utils';
@@ -174,7 +222,12 @@ const addressFromNumber = await getAddressInfoByCep(1310100);
### getCepInfoByAddress
-Fetch CEPs from an address using ViaCEP. Throws `GetCepInfoByAddressValidationError` when the UF, city or street is missing/invalid — including when the argument is not an object at all (omitted, `null`, a string) and when `federalUnit` is not a string, neither of which leaks a raw `TypeError` — `GetCepInfoByAddressNotFoundError` when no address matches the query, and `GetCepInfoByAddressError` when ViaCEP itself answers with an HTTP error status. A request that cannot be performed at all (a transport failure) rejects with the underlying `fetch` error instead. Each item is typed as `CepAddressInfo` and carries the ViaCEP payload unchanged, under ViaCEP's own field names: `cep`, `logradouro`, `complemento`, `unidade`, `bairro`, `localidade`, `uf`, `estado`, `regiao`, `ibge`, `gia`, `ddd` and `siafi`. A broad street name matches many CEPs, so query as narrowly as the address allows.
+Fetch the CEPs of an address from ViaCEP. Resolves to an array of `CepAddressInfo`.
+
+- The argument (`GetCepInfoByAddressParams`) carries `federalUnit`, `city` and `street`. `federalUnit` may be lowercase; `city` and `street` are trimmed and stripped of accents before the query.
+- Rejects with `GetCepInfoByAddressValidationError` when the UF, city or street is missing or invalid, with `GetCepInfoByAddressNotFoundError` when no address matches, and with `GetCepInfoByAddressError` when ViaCEP answers with an HTTP error status.
+- Retries transient network failures, as `getAddressInfoByCep` does.
+- Each item carries the ViaCEP payload unchanged, under ViaCEP's own field names.
```javascript
import { getCepInfoByAddress } from '@brazilian-utils/brazilian-utils';
@@ -208,7 +261,10 @@ const ceps = await getCepInfoByAddress({
### isValidBoleto
-Check if boleto ([brazilian payment method](https://en.wikipedia.org/wiki/Boleto)) is valid. Supports both the 47 digit "cobrança bancária" boleto and the "boleto de arrecadação" (convênio/tributos): either its 48 digit linha digitável or its 44 digit barcode, both starting with `8`. One leniency is kept from 2.3.0: the código de moeda in position 4 of the cobrança bancária barcode is not checked, although Carta-Circular BCB nº 2.926/2000 fixes it at `9` (real), so a slip carrying any other moeda digit still validates.
+Check if a boleto ([brazilian payment method](https://en.wikipedia.org/wiki/Boleto)) is valid.
+
+- Accepts the 47 digit "cobrança bancária" linha digitável and, for the "boleto de arrecadação", either its 48 digit linha digitável or its 44 digit barcode.
+- The código de moeda (position 4 of the cobrança bancária barcode) is not checked.
```javascript
import { isValidBoleto } from '@brazilian-utils/brazilian-utils';
@@ -217,9 +273,14 @@ isValidBoleto('00190000090114971860168524522114675860000102656'); // true
isValidBoleto('846100000005246100291102005460339004695895061080'); // true (boleto de arrecadação)
```
+Source: [Carta-Circular BCB nº 2.926/2000](https://www.bcb.gov.br/pre/normativos/c_circ/2000/pdf/c_circ_2926_v1_O.pdf), [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
### formatBoleto
-Format a boleto number. `options.pad` (part of `FormatBoletoOptions`) left-pads the value with zeros up to the number of slots in the pattern before masking (default `false`). The arrecadação (convênio/tributos) mask applies only to the 48 digit linha digitável starting with `8`; the 44 digit arrecadação barcode has no display grouping defined by FEBRABAN and keeps the "cobrança bancária" mask instead.
+Format a boleto number.
+
+- **Options** (`FormatBoletoOptions`): `pad` left-pads the value with zeros to the length of the pattern before masking (default `false`).
+- A 48 digit linha digitável starting with `8` gets the arrecadação mask: four blocks of 11 digits, each followed by its check digit. The 44 digit arrecadação barcode keeps the "cobrança bancária" mask.
```javascript
import { formatBoleto } from '@brazilian-utils/brazilian-utils';
@@ -230,6 +291,8 @@ formatBoleto('846100000005246100291102005460339004695895061080'); // 84610000000
formatBoleto('84610000000246100291100054603390069589506108'); // 84610.00000 02461.002911 00054.603390 0 69589506108 (44 digit arrecadação barcode keeps the bancária mask)
```
+Source: [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
### parseBoleto
Remove boleto formatting, keep only digits, and cap the result to 47 digits (48 for boleto de arrecadação).
@@ -242,7 +305,9 @@ parseBoleto('00190.00009 01149.718601 68524.522114 6 75860000102656'); // 001900
### generateBoleto
-Generate a valid random boleto. Pass `{ type: "arrecadacao" }` (typed as `GenerateBoletoParams`) to generate a boleto de arrecadação instead of the default "bancario" (cobrança bancária) type. An arrecadação slip draws its segment from 1 to 7 (segment 9 is the banks' own) and its value identifier from all four values, `6` and `8` for an effective amount and `7` and `9` for a reference quantity, so both `hasEffectiveValue` branches of `getBoletoInfo` are reachable.
+Generate a valid random boleto.
+
+- Pass `{ type: 'arrecadacao' }` (`GenerateBoletoParams`) for a 48 digit boleto de arrecadação instead of the default `'bancario'` (cobrança bancária, 47 digits).
```javascript
import { generateBoleto } from '@brazilian-utils/brazilian-utils';
@@ -253,7 +318,12 @@ generateBoleto({ type: 'arrecadacao' }); // "84610000000524610029110200546033900
### getBoletoInfo
-Extract information from a boleto (amount, expiration date, bank code). Returns `null` when `value` is not a valid boleto — `isValidBoleto` is checked first — so the result has to be narrowed before it is read. 2.3.0 returned `undefined` here; every getter of the package now answers an unresolved lookup with `null`, so only a strict `=== undefined` comparison is affected. Accepts an optional `{ referenceDate }` (typed as `GetBoletoInfoOptions`) to resolve the "fator de vencimento" cycle as of a specific date instead of now (the factor's date-base cycle reset on 22/02/2025 per FEBRABAN). Neither FEBRABAN nor the Banco Central publishes a way of telling an old cycle factor from a new cycle one, so every factor resolves to either of two dates 9000 days apart and `referenceDate` picks between them through the library's own safety windows: the same slip can resolve to the other candidate as time passes, so pass `referenceDate` explicitly whenever the answer has to stay stable. The cycle search never goes below the first cycle, so a `referenceDate` older than the scheme itself still resolves a factor to the oldest date that factor can denote rather than to one before the 07/10/1997 base date. For a boleto de arrecadação, the result, typed as `BoletoInfo`, still carries both keys but empty, `bankCode: ''` and `expirationDate: null`, since the slip has neither a bank code nor a fator de vencimento, and adds `type: "arrecadacao"`, `segment`, `value` and `hasEffectiveValue`.
+Extract information from a boleto (amount, expiration date, bank code). Returns `null` when the value is not a valid boleto.
+
+- **Options** (`GetBoletoInfoOptions`): `referenceDate` resolves the "fator de vencimento" cycle as of that date instead of now.
+- Returns a `BoletoInfo`: `amount` in cents, `expirationDate` and the three digit `bankCode`. `expirationDate` is `null` when the slip carries no fator de vencimento (a factor below `1000`).
+- The fator de vencimento cycle reset on 22/02/2025, so a factor can mean either of two dates 9000 days apart. `referenceDate` picks between them; pass it whenever the answer has to stay stable.
+- A boleto de arrecadação has `bankCode: ''` and `expirationDate: null`, plus `type: 'arrecadacao'`, `segment`, `value` (the amount in reais) and `hasEffectiveValue`.
```javascript
import { getBoletoInfo } from '@brazilian-utils/brazilian-utils';
@@ -272,11 +342,16 @@ getBoletoInfo('846100000005246100291102005460339004695895061080');
getBoletoInfo('invalid'); // null
```
+Source: [Carta-Circular BCB nº 2.926/2000](https://www.bcb.gov.br/pre/normativos/c_circ/2000/pdf/c_circ_2926_v1_O.pdf), [FEBRABAN, Layout Padrão de Arrecadação](https://cmsarquivos.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%208%20-%2011_05_2026.pdf).
+
## Pix
### isValidPixKey
-Check if a Pix key (chave Pix) is valid: a CPF, a CNPJ, an e-mail address, a Brazilian mobile phone number or a random key (EVP), per the DICT key formats. The manual registers a "número de telefone celular", so a landline is not a valid phone key. `options.accept` (typed as `IsValidPixKeyOptions`) restricts which kinds of key are accepted; it defaults to all of them, and `[]` rejects everything. Exports the `PixKeyType` type.
+Check if a Pix key (chave Pix) is valid: a CPF, a CNPJ, an e-mail address, a Brazilian mobile phone number or a random EVP key, per the DICT key formats.
+
+- **Options** (`IsValidPixKeyOptions`): `accept` (`PixKeyType[]`, default all of them) lists the kinds of key that count as valid; `[]` rejects everything.
+- Same recognition rules as `getPixKeyInfo`.
```javascript
import { isValidPixKey } from '@brazilian-utils/brazilian-utils';
@@ -290,9 +365,16 @@ isValidPixKey('123.456.789-09', { accept: ['email', 'evp'] }); // false
isValidPixKey('not a key'); // false
```
+Source: [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf), [DICT API](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT.html), [pix-api](https://github.com/bacen/pix-api).
+
### getPixKeyInfo
-Identifies a Pix key and normalizes it to the canonical form the DICT expects inside a BR Code: 11 digit CPF, 14 character CNPJ, lowercased e-mail, E.164 mobile phone (a landline is not a Pix key) or lowercase UUID EVP. An 11 digit value that is valid both as a CPF and as a mobile phone is read as a CPF, unless it was written as a phone number (a `+55`/`0055` prefix or a DDD wrapped in parentheses). The CPF and the phone number are recognized by the way they are written, not only by the digits they carry, so surrounding text is not stripped away and `'abc123.456.789-09'` is not a CPF key. An e-mail key is trimmed and lowercased, and one longer than the 77 characters the DICT allows is rejected. A value whose digits carry a valid CNPJ check digit is read as a CNPJ even when it starts with `0055`, since a phone key inside a BR Code always carries the `+55` prefix. Returns `null` when the value is not a valid Pix key. The result is typed as `PixKeyInfo`.
+Identify a Pix key and normalize it to the canonical form the DICT expects inside a BR Code. Returns `null` when the value is not a valid Pix key.
+
+- Returns a `PixKeyInfo` with the `type` (`PixKeyType`) and the `value`.
+- The canonical `value` is digits for a CPF or CNPJ (letters upper-cased), a lowercase e-mail, an E.164 phone or a lowercase UUID.
+- An 11 digit value valid as both CPF and mobile phone is read as a CPF, unless written as a phone (`+55` prefix or DDD in parentheses).
+- An e-mail longer than 77 characters is rejected.
```javascript
import { getPixKeyInfo } from '@brazilian-utils/brazilian-utils';
@@ -307,9 +389,17 @@ getPixKeyInfo('51998259765'); // { type: 'cpf', value: '51998259765' } (also a v
getPixKeyInfo('+5551998259765'); // { type: 'phone', value: '+5551998259765' }
```
+Source: [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf), [DICT API](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT.html).
+
### isValidPixPayload
-Check if a Pix BR Code payload (the string behind a Pix QR Code and behind "Pix copia e cola") is valid: well-formed TLV structure, the mandatory objects present, one of the "Merchant Account Information" templates carrying the `br.gov.bcb.pix` GUI with a key or a URL, and a matching CRC-16. The "Point of Initiation Method" object (`01`) is advisory: the Manual do BR Code marks it optional and only assigns a meaning to the value `"12"` ("só pode ser utilizado uma vez"), so it may be absent from either shape and only a value outside `{"11", "12"}` makes the payload invalid. When a payload built around a key carries an amount (`54`), that amount must be greater than zero, unless the payload is a Pix Saque BR Code, i.e. unless it carries the ISPB of the "facilitador de serviço de saque" in sub-object 26-03 (`fss`) as §2.6 of the Pix manual prescribes; rejecting `"0"`/`"0.00"` without `fss` is a deliberate restriction of this library, not a rule of the manual. A `fss` written next to a PSP location makes the payload invalid: §2.7 of the Manual de Padrões para Iniciação do Pix maps the dynamic QR Code to exactly two sub-objects, `00` (GUI) and `25` (URL), and `fss` belongs to the static template of §2.6. The key itself is not checked against the DICT formats, use `isValidPixKey` for that. Unreserved Templates (IDs 80 to 99) are ignored: the "QR Code composto" of Pix Automático (Pix recorrente) writes its recurrence location in one of them, and when such a payload also carries a payment location in 26-25, as the composite example of the Pix manual does, it is accepted and read as an ordinary dynamic payload with the recurrence location dropped. Only a payload with no Pix template at all in IDs 26 to 51 is reported as invalid.
+Check if a Pix BR Code payload (the string behind a Pix QR Code and behind "Pix copia e cola") is valid. The key itself is not checked; use `isValidPixKey`.
+
+- The TLV structure, the CRC-16 and the mandatory objects (format indicator, category code, currency, country, merchant name and city) are checked.
+- One "Merchant Account Information" template (IDs 26 to 51) must carry the `br.gov.bcb.pix` GUI with a key (static) or a PSP URL (dynamic), never both.
+- Objects `01` (Point of Initiation Method) and `62` (Additional Data Field) are optional; `01` must be `11` or `12` when present.
+- An amount (`54`) must be greater than zero, except in a Pix Saque BR Code (8 digit `fss` in sub-object 26-03).
+- Unreserved Templates (IDs 80 to 99) are ignored.
```javascript
import { isValidPixPayload } from '@brazilian-utils/brazilian-utils';
@@ -322,9 +412,16 @@ isValidPixPayload(
isValidPixPayload('00020126580014br.gov.bcb.pix...'); // false (broken CRC)
```
+Source: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
### getPixPayloadInfo
-Parses a Pix BR Code payload into its fields. The payload is validated by `isValidPixPayload` first, so a malformed structure, a broken CRC or a missing mandatory object returns `null` instead of a partial result. A static payload comes back with `key`, a dynamic one with `url`. The Pix key itself is not validated, since the manual allows a static QR Code built around a key that no longer exists in the DICT; key ownership is only settled at payment time. The "Additional Data Field Template" (ID 62) is mandatory in the BR Code table but optional in the EMV® specification it refers to, so it is accepted when absent. The lengths the manual reserves for the merchant name (25), the merchant city (15), the `txid` (25) and the Pix key field 26-01 (77) are generator side limits, enforced by `generatePixPayload` and not checked here, since payloads in the wild routinely overrun them. The result is typed as `PixPayloadInfo`; `pointOfInitiation` is always present and typed as `PixPointOfInitiation`, `"dynamic"` when the payload carries a PSP location or when the "Point of Initiation Method" object (`01`) is `"12"`, `"static"` otherwise. The merchant account information must carry exactly one of a key or a `url` (checked with the same PSP location rule as `generatePixPayload`); `01` itself is advisory, so it may be absent from either shape and only a value outside `{"11", "12"}` returns `null`. When a payload built around a key carries an amount, that amount must be greater than zero, unless the payload is a Pix Saque BR Code: §2.6 of the Pix manual puts the ISPB of the "facilitador de serviço de saque" in sub-object 26-03 (`fss`), which comes back as `withdrawalFacilitator`, and `54` set to `"0"` or `"0.00"` is accepted alongside it. Rejecting a zero amount without `fss` is a deliberate restriction of this library, not a rule of the manual. A `fss` written next to a PSP location returns `null`: §2.7 of the Manual de Padrões para Iniciação do Pix maps the dynamic QR Code to exactly two sub-objects, `00` (GUI) and `25` (URL), and `fss` belongs to the static template of §2.6. When the payload carries a PSP location the amount and the `txid` are ignored, as the manual mandates. Unreserved Templates (IDs 80 to 99) are ignored: a "QR Code composto" of Pix Automático that also carries a payment location in 26-25 is parsed as an ordinary dynamic payload and its recurrence location is dropped, so a consumer that has to tell the two apart cannot rely on this parser. Only a payload with no Pix template at all in IDs 26 to 51 returns `null`.
+Parse a Pix BR Code payload into its fields. Accepts what `isValidPixPayload` accepts and returns `null` for anything else, never a partial result.
+
+- Returns a `PixPayloadInfo`: `merchantName`, `merchantCity`, `pointOfInitiation` and either `key` (static) or `url` (dynamic).
+- `amount`, `txid`, `description` and `withdrawalFacilitator` (the `fss` of a Pix Saque) are present only when the payload carries them. `txid` is absent for the `***` marker.
+- `pointOfInitiation` (`PixPointOfInitiation`) is `"dynamic"` when the payload carries a PSP location or object `01` is `"12"`, `"static"` otherwise.
+- With a PSP location, `amount` and `txid` are ignored, as the manual mandates.
```javascript
import { getPixPayloadInfo } from '@brazilian-utils/brazilian-utils';
@@ -341,11 +438,18 @@ getPixPayloadInfo(
// }
```
+Source: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
### generatePixPayload
-Generates the payload of a Pix BR Code. Exactly one of `params.key` or `params.url` must be given (part of `GeneratePixPayloadParams`); `null` is returned when both or neither are given. `url` must be a PSP location as the Bacen manual defines it: a host name with a path, without a scheme (`pix.example.com/qr/v2/1234`); a dynamic payload cannot carry `amount` or `txid`, which belong to the PSP location. The amount is written with the two decimal places the BR Code takes, so one that rounds to `0.00` and one that does not survive that round trip (`0.005`, `123.456`) are both rejected rather than written as a different sum. The Pix Saque BR Code, which announces the `fss` of sub-object 26-03, is parsed by `getPixPayloadInfo` but not generated here.
+Generate the payload of a Pix BR Code. Exactly one of `params.key` or `params.url` must be given; `null` is returned when both or neither are given.
-When `params.key` is given, it is normalized to its DICT canonical form by `getPixKeyInfo` and the payload is static. When `params.url` is given instead (the PSP location, without a URL scheme, e.g. `"pix.example.com/qr/v2/1234"`), the payload is dynamic per the Manual de Padrões para Iniciação do Pix: the URL takes the key's place in the "Merchant Account Information" template and the "Point of Initiation Method" object is set to dynamic (`12`); `params.url` can be at most 77 characters. `merchantName`, `merchantCity` and `description` are folded to printable ASCII (accents dropped) and truncated to what the BR Code allows. `getPixPayloadInfo` already parses both shapes, so `getPixPayloadInfo(generatePixPayload({ url, ... }))` round-trips.
+- **Params** (`GeneratePixPayloadParams`): `key` or `url`, `merchantName`, `merchantCity`, and the optional `amount`, `txid` and `description`.
+- With `key` the payload is static and the key is normalized by `getPixKeyInfo`. With `url` it is dynamic (object `01` set to `12`) and cannot carry `amount` or `txid`.
+- `url` is a PSP location: host and path, no scheme (`pix.example.com/qr/v2/1234`), at most 77 characters.
+- `amount` takes two decimal places; `0.005`, `123.456` or a value that rounds to `0.00` is rejected.
+- `txid` is 1 to 25 characters of `[A-Za-z0-9]` (default `***`).
+- `merchantName`, `merchantCity` and `description` lose their accents and are truncated to 25, 15 and what is left of the template.
```javascript
import { generatePixPayload } from '@brazilian-utils/brazilian-utils';
@@ -368,13 +472,28 @@ generatePixPayload({
generatePixPayload({ merchantName: 'Fulano', merchantCity: 'Brasília' }); // null (neither key nor url)
```
+Source: [Manual do BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf), [Manual de Padrões para Iniciação do Pix](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf).
+
## NF-e key
### isValidNfeKey
-Check if a DF-e (Documento Fiscal eletrônico) access key (chave de acesso) is valid. It covers every document whose access key is the same 44 digit string: NF-e (modelo 55), NFC-e (65), CT-e (57, the Conhecimento de Transporte Eletrônico instituted by the cláusula primeira of the [Ajuste SINIEF 09/07](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2007/AJ_009_07)), MDF-e (58), CT-e OS (67, the Conhecimento de Transporte Eletrônico para Outros Serviços instituted by the cláusula primeira of the [Ajuste SINIEF 36/19](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2019/AJ036_19)), GTV-e (64, the CT-e Guia de Transporte de Valores instituted by the cláusula primeira of the [Ajuste SINIEF 03/20](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2020/ajuste-sinief-03-20)), BP-e (63), NF3e (66) and NFCom (62). The CF-e-SAT (59) is out: its 44 position "chave de consulta" is composed differently. The 44 digits may be split into the printed groups of 4 by whitespace, `.`, `-` or `/`, a run of them between two groups included, the same interchangeable mask `isValidCpf` and `isValidCnpj` accept; a separator inside a group of 4, or any other character, is rejected instead of being stripped. The `NFe`, `CTe`, `MDFe`, `BPe`, `NF3e` and `NFCom` prefixes found in the `Id` attribute of the document's XML are stripped before that check, along with any whitespace between the prefix and the first group.
+Check if a DF-e access key (chave de acesso) is valid. Covers every DF-e with a 44 digit access key; the CF-e-SAT (59) is out.
-The emission type (`tpEmis`) is checked against the codes the MOC of that model assigns, so the accepted set changes with the model: 1 to 7 and 9 for NF-e and NFC-e, `{1, 3, 4, 5, 7, 8}` for the CT-e, `{1, 5, 7, 8}` for the CT-e OS, `{1, 2, 7, 8}` for the GTV-e, `{1, 2, 3}` for the MDF-e and `{1, 2}` for the BP-e, the NF3e and the NFCom. Code 8, the authorização pela SVC-SP, is assigned by the [CT-e MOC 4.00](https://dfe-portal.svrs.rs.gov.br/CTE/Documentos) only, never by the NF-e one; the domains of the [BP-e](https://dfe-portal.svrs.rs.gov.br/BPE/Documentos), the [NF3e](https://dfe-portal.svrs.rs.gov.br/NF3e/Documentos) and the [NFCom](https://dfe-portal.svrs.rs.gov.br/NFCOM/Documentos) come from their own manuals. For NF-e and NFC-e the numeric code is also checked against rule B03-10 of the NF-e MOC, which forbids the twenty repeated and sequential `cNF` values it lists and a `cNF` equal to the document number. A document number of all zeros is turned down for every model, following the leiaute rather than a choice of this library: `tiposBasico_v4.00.xsd` of the [NF-e schema package](https://dfe-portal.svrs.rs.gov.br/NFE/Documentos) types `nNF` as `TNF`, whose pattern is `[1-9]{1}[0-9]{0,8}`, and the Anexo I of every other model repeats the same regex for its own number field.
+- Models: NF-e (55), NFC-e (65), CT-e (57), MDF-e (58), CT-e OS (67), GTV-e (64), BP-e (63), NF3e (66) and NFCom (62).
+- The 44 digits may be grouped in 4 by whitespace, `.`, `-` or `/`. The XML `Id` prefixes (`NFe`, `CTe`, `MDFe`, `BPe`, `NF3e`, `NFCom`) are stripped first.
+- `tpEmis` must be one the MOC of that model assigns (table below).
+- For NF-e and NFC-e the `cNF` must pass rule B03-10 of the MOC (no repeated or sequential values, not the document number).
+- A document number of all zeros is rejected. The check digit is a modulus 11 over the first 43 digits.
+
+| Model | `tpEmis` accepted |
+| --- | --- |
+| NF-e (55), NFC-e (65) | 1 to 7 and 9 |
+| CT-e (57) | 1, 3, 4, 5, 7, 8 |
+| CT-e OS (67) | 1, 5, 7, 8 |
+| GTV-e (64) | 1, 2, 7, 8 |
+| MDF-e (58) | 1, 2, 3 |
+| BP-e (63), NF3e (66), NFCom (62) | 1, 2 |
```javascript
import { isValidNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -386,13 +505,20 @@ isValidNfeKey('3517 0458 7165 2300 0119 5500 1000 0000 1210 0012 3458'); // true
isValidNfeKey('3517.0458.7165.2300.0119.5500.1000.0000.1210.0012.3458'); // true (any of the mask characters)
isValidNfeKey('351 70458716523000119550010000000121000123458'); // false (a separator inside a group of 4)
isValidNfeKey('99170458716523000119550010000000121000123458'); // false (invalid cUF)
+isValidNfeKey('35170458716523000119010010000000121000123450'); // false (invalid mod)
isValidNfeKey('35170458716523000119550010000000128000123455'); // false (the NF-e MOC does not assign tpEmis 8)
isValidNfeKey('35170458716523000119550010000000121000000003'); // false (cNF 00000000, rule B03-10)
```
+Source: [MOC NF-e](https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-visao-geral.pdf), [NF-e schemas](https://dfe-portal.svrs.rs.gov.br/NFE/Documentos) and the MOCs cited in `src/is-valid-nfe-key/is-valid-nfe-key.ts`.
+
### formatNfeKey
-Format a DF-e (Documento Fiscal eletrônico) access key into groups of 4 digits separated by spaces, the form every auxiliary document prints it in: the DANFE of the NF-e and the NFC-e, the DACTE of the CT-e, the CT-e OS and the GTV-e, the DAMDFE of the MDF-e, the DABPE of the BP-e, the DANF3E of the NF3e and the DANFE-COM of the NFCom. Like every formatter of this package, the value is read for its digits and grouped as far as they go, so a masked or partial key still being typed is grouped progressively, and anything without a digit (an object, `true`, an object created with `Object.create(null)`) gives `''` instead of throwing. Use `isValidNfeKey` to check a key. `options.pad` (part of `FormatNfeKeyOptions`) left pads the value with zeros up to the 44 digits of a complete access key (default `false`). The parameter is typed as a string because 44 digits are more than a JavaScript number can hold exactly; at runtime a number is read as the string of its digits, like in every formatter of this package.
+Format a DF-e (Documento Fiscal eletrônico) access key into groups of 4 digits separated by spaces, the form the DANFE, DACTE, DAMDFE, DABPE, DANF3E and DANFE-COM print it in.
+
+- **Options** (`FormatNfeKeyOptions`): `pad` left pads the value with zeros up to the 44 digits of a complete access key (default `false`).
+- A masked or partial key is grouped as far as its digits go.
+- Use `isValidNfeKey` to check a key.
```javascript
import { formatNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -408,7 +534,9 @@ formatNfeKey('12345', { pad: true });
### parseNfeKey
-Remove the formatting of a DF-e access key (chave de acesso), keep only digits, and cap the result to 44 digits. The `NFe`, `CTe`, `MDFe`, `BPe`, `NF3e` and `NFCom` prefixes the `Id` attribute of the document XML puts in front of the key are stripped first, since `NF3e` carries a digit of its own; use `isValidNfeKey` to check the key and `getNfeKeyInfo` to read its fields.
+Remove the formatting of a DF-e access key (chave de acesso), keep only digits, and cap the result to 44 digits.
+
+- The XML `Id` prefixes (`NFe`, `CTe`, `MDFe`, `BPe`, `NF3e`, `NFCom`) are stripped first.
```javascript
import { parseNfeKey } from '@brazilian-utils/brazilian-utils';
@@ -422,7 +550,10 @@ parseNfeKey('NFe35170458716523000119550010000000121000123458');
### getNfeKeyInfo
-Parses a DF-e access key into its fields (stateCode, year, month, taxId, model, series, number, emissionType, code, checkDigit). Accepts the same input forms as `isValidNfeKey` and returns `null` when the key is not valid. The result is typed as `NfeKeyInfo`, whose `model` is an `NfeKeyModel`. NFCom (`'62'`) and NF3e (`'66'`) spend position 36 of the key on `nSiteAutoriz`, the site of the authorizer that received the document, so for those two models the result also carries `authorizationSite` and `code` is 7 digits instead of 8.
+Parse a DF-e access key into its fields. Accepts the same input forms as `isValidNfeKey` and returns `null` when the key is not valid.
+
+- Returns an `NfeKeyInfo`: `stateCode`, `year`, `month`, `taxId`, `model` (`NfeKeyModel`), `series`, `number`, `emissionType`, `code` and `checkDigit`.
+- For NFCom and NF3e (models `'62'` and `'66'`) the result also carries `authorizationSite` and `code` is 7 digits instead of 8.
```javascript
import { getNfeKeyInfo } from '@brazilian-utils/brazilian-utils';
@@ -442,7 +573,9 @@ getNfeKeyInfo('invalid'); // null
### isValidPhone
-Check if phone number (mobile or landline) is valid. A Brazilian country code (`+55`, `0055` or a bare `55`) is accepted and removed before validation, under the rule documented in `parsePhone`. `options.accept` (typed as `PhoneType[]`, part of `IsValidPhoneOptions`) picks which kinds of number count as valid and defaults to `['mobile', 'landline']`; add `'service'` to also accept the non-geographic numbers recognized by `isValidServicePhone`, or pass `[]` to accept none. `options.version` (typed as `PhoneVersion`, part of the same type) is forwarded to `isValidMobilePhone` and picks which mobile numbering rule is enforced: `1` (default) the legacy format, whose first number digit may be 6, 7, 8 or 9, and `2` the current one of Resolução Anatel 749/2022, art. 12, I, "a", which accepts 7, 8 or 9 and rejects the `700` prefix. It only affects mobile numbers; landline and service numbers are unaffected.
+Check if a phone number (mobile or landline) is valid. A Brazilian country code (`+55`, `0055` or a bare `55`) is accepted and removed first, as in `parsePhone`.
+
+- **Options** (`IsValidPhoneOptions`): `accept` (`PhoneType[]`, default `['mobile', 'landline']`) picks which kinds of number count as valid; add `'service'` for the numbers `isValidServicePhone` recognizes. `version` (`PhoneVersion`, default `1`) is forwarded to `isValidMobilePhone`.
```javascript
import { isValidPhone } from '@brazilian-utils/brazilian-utils';
@@ -456,9 +589,17 @@ isValidPhone('08001234567', { accept: ['service'] }); // true
isValidPhone('11900000000', { accept: [] }); // false
```
+Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### formatPhone
-Format phone number according to Brazilian patterns. `options.mask` (typed as `PhoneMask`) accepts `"sn"` (default, subscriber number only, 9 digits, no DDD), `"nanp"` (DDD + subscriber number, `"(00) 00000-0000"` for the 11 digits of a mobile and `"(00) 0000-0000"` for the 10 digits of a landline, any other length keeping the 11 digit grouping), `"e164"` (`"+5511987654321"`), `"international"` (`"+55 11 98765-4321"`, the way a Brazilian number is printed for foreign callers), `"service"` (`"0800 123 4567"` or `"4004-1234"`, the conventional groupings for service numbers) or `"auto"`. `"auto"` picks `"international"` when `value` carries a Brazilian country code (`+55`, `0055` or a bare `55` followed by 10 or 11 digits), `"service"` when `value` is a service number, and otherwise falls back to the digit count: `"nanp"` when `value` has more digits than a bare subscriber number, `"sn"` when it does not. `"e164"` and `"international"` drop the country code from `value` first, under the rule documented in `parsePhone`, and fall back to the `"service"` presentation for a service number, since those have no E.164 form. If `value` includes a DDD, pass `{ mask: 'auto' }` (or `'nanp'`) explicitly, since the default `"sn"` mask assumes no DDD and silently truncates one if present. A `mask` outside the union falls back to the default `"sn"` instead of throwing.
+Format a phone number according to Brazilian patterns. If `value` includes a DDD, pass `{ mask: 'auto' }` or `'nanp'`: the default `"sn"` mask assumes no DDD and truncates one.
+
+- **Options** (`FormatPhoneOptions`): `mask` (`PhoneMask`, default `"sn"`) picks one of the patterns below. An unknown `mask` falls back to `"sn"`.
+- `"sn"`: subscriber number only, 9 digits. `"nanp"`: DDD plus subscriber number, 11 digits for a mobile and 10 for a landline; any other length keeps the 11 digit grouping.
+- `"e164"` and `"international"` drop the country code first, as `parsePhone` does, and fall back to `"service"` for a service number.
+- `"service"`: the Códigos Não Geográficos (`0800 123 4567`) and the abbreviated `300X`/`400X` numbers (`4004-1234`).
+- `"auto"`: `"service"` for a service number, `"international"` when `value` carries a country code, otherwise `"nanp"` for more than 9 digits, else `"sn"`.
```javascript
import { formatPhone } from '@brazilian-utils/brazilian-utils';
@@ -473,12 +614,17 @@ formatPhone('+5511987654321', { mask: 'international' }); // +55 11 98765-4321
formatPhone('08001234567', { mask: 'service' }); // 0800 123 4567
formatPhone('40041234', { mask: 'service' }); // 4004-1234
formatPhone('+5511987654321', { mask: 'auto' }); // +55 11 98765-4321 ("auto" detects the +55 prefix and picks "international")
+formatPhone('5508001234567', { mask: 'auto' }); // 0800 123 4567 ("auto" reads the 0800 number, not a +55 08 one)
formatPhone('11900000000'); // 11900-0000 (BEWARE: default "sn" truncates a DDD-prefixed number)
```
+Source: [ITU-T E.164](https://www.itu.int/rec/T-REC-E.164), [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### parsePhone
-Remove phone formatting, keep only digits, and cap the result to 11 digits. A Brazilian country code is stripped first, but only when the digits left behind are exactly 10 or 11 long, i.e. a plausible national number. The rule is length-based, not sign-based, so a number from area code 55 is not mistaken for a country code.
+Remove phone formatting, keep only digits, and cap the result to 11 digits.
+
+- A Brazilian country code (`+55`, `0055` or a bare `55`) is stripped first, but only when 10 or 11 digits are left (DDD plus subscriber number), so area code 55 is not mistaken for it.
```javascript
import { parsePhone } from '@brazilian-utils/brazilian-utils';
@@ -491,7 +637,9 @@ parsePhone('55987654321'); // 55987654321 (area code 55, not mistaken for the +5
### generatePhone
-Generate a random Brazilian phone number. Accepts `'mobile'`, `'landline'` or `'service'` (typed as `GeneratePhoneType`); a service number has no DDD. Omitted, it randomly generates a mobile or a landline, never a service number. A generated mobile number always starts with 9, so it passes both `isValidMobilePhone` numbering rules.
+Generate a random Brazilian phone number. Accepts `'mobile'`, `'landline'` or `'service'` (`GeneratePhoneType`); when omitted, it generates a mobile or a landline at random, never a service number.
+
+- A mobile starts with 9 after the DDD (valid under both `isValidMobilePhone` versions); a landline has 8 digits after the DDD, starting with 2 to 6; a service number has no DDD.
```javascript
import { generatePhone } from '@brazilian-utils/brazilian-utils';
@@ -504,7 +652,9 @@ generatePhone('service'); // '08001234567' or '40041234'
### isValidMobilePhone
-Check if mobile phone number is valid. `options.version` (typed as `PhoneVersion`) controls which mobile numbering rule is enforced: `1` (default) is the pre-Resolução Anatel 749/2022 format, kept for 2.3.0 compatibility, whose first number digit (after the DDD) may be 6, 7, 8 or 9; `2` enforces the resolution's art. 12, I, "a", which places 7, 8 and 9 in the Serviço Móvel Pessoal (SMP), so a leading 6 is Reserva Técnica and is rejected. Version `2` also carves out the `700` prefix, which art. 12, II reserves for the Serviço Móvel Global por Satélite rather than SMP, so `isValidMobilePhone('11700123456', { version: 2 })` is `false`; version `1` does not carve it out and accepts it.
+Check if a mobile phone number is valid. A Brazilian country code (`+55`, `0055` or a bare `55`) is accepted and removed first, as in `parsePhone`.
+
+- **Options** (`IsValidMobilePhoneOptions`): `version` (`PhoneVersion`, default `1`) picks the numbering rule: `1` accepts a first digit of 6, 7, 8 or 9; `2` follows Resolução Anatel 749/2022, accepts only 7, 8 or 9 and rejects the `700` series.
```javascript
import { isValidMobilePhone } from '@brazilian-utils/brazilian-utils';
@@ -516,19 +666,26 @@ isValidMobilePhone('11612345678', { version: 2 }); // false (6 is Reserva Técni
isValidMobilePhone('11700123456', { version: 2 }); // false (the 700 series is satellite)
```
+Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749).
+
### isValidLandlinePhone
-Check if landline phone number is valid.
+Check if a landline phone number is valid. A Brazilian country code (`+55`, `0055` or a bare `55`) is accepted and removed first, as in `parsePhone`.
```javascript
import { isValidLandlinePhone } from '@brazilian-utils/brazilian-utils';
isValidLandlinePhone('1130000000'); // true
+isValidLandlinePhone('+55 11 3000-0000'); // true (country code accepted)
```
### isValidServicePhone
-Check if a phone number is a valid Brazilian service number, dialed without a DDD: the Códigos Não Geográficos `0300`, `0303`, `0500`, `0800` and `0900` (11 digits total, so the shorter, extinct `0800` + 6 digit form is rejected), the abbreviated `300X`/`400X` numbers (8 digits), and the 3-digit Códigos de Acesso a Serviços de Utilidade Pública that Anatel has designated (e.g. `190`, `192`), whose consolidated table is the Anexo of [Ato Anatel nº 43.151/2004](https://informacoes.anatel.gov.br/legislacao/atos-de-numeracao/2004/1648-ato-43151). `112` and `911` are rejected: Anatel designates neither, and `911` is not even inside the `1N₂N₁` range art. 13 of [Resolução nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749) destines to public utility services, so the way handsets route them is a GSM convention rather than a numbering designation. Only the structure is checked: the number does not have to be assigned to anyone, and the `0500` rule that encodes a donation amount in the last two digits is not enforced. Anatel withdrew the 4-digit codes instead of allocating them (art. 43 I of [Resolução nº 86/1998](https://informacoes.anatel.gov.br/legislacao/resolucoes/1998/336-resolucao-86) and art. 2º II of the Ato above both ordered them released), so only the conventional `300X` and `400X` roots are recognised: other "Número Único" carrier prefixes in market use, such as `4020` and `4062`, are out of scope and are rejected.
+Check if a phone number is a valid Brazilian service number, dialed without a DDD. Only the structure is checked: the number does not have to be assigned to anyone.
+
+- The Códigos Não Geográficos `0300`, `0303`, `0500`, `0800` and `0900` followed by 7 digits (11 in total).
+- The abbreviated `300X`/`400X` numbers, 8 digits. Other carrier prefixes such as `4020` and `4062` are rejected.
+- The 3 digit public utility codes Anatel has designated (e.g. `190`, `192`). `112` and `911` are not among them and are rejected.
```javascript
import { isValidServicePhone } from '@brazilian-utils/brazilian-utils';
@@ -539,11 +696,14 @@ isValidServicePhone('190'); // true
isValidServicePhone('11987654321'); // false (geographic number)
```
+Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Ato Anatel nº 43.151/2004](https://informacoes.anatel.gov.br/legislacao/atos-de-numeracao/2004/1648-ato-43151), [Resolução nº 86/1998](https://informacoes.anatel.gov.br/legislacao/resolucoes/1998/336-resolucao-86).
+
### getAreaCodeInfo
-Get the state (and its 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 number, stripping any non-digit characters before matching. Exports the `AreaCodeInfo` type.
+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.
-`stateCode` is always a single state: the one the DDD is seated in, the state of the city the code was allocated around, which is not necessarily the state holding most of its municipalities. Four DDDs straddle a state border, and for those `stateCodes` lists the other states too. DDD 61 is the widest of them, serving the Distrito Federal and the twelve Goiás municipalities of the Entorno do Distrito Federal (Águas Lindas de Goiás, Cabeceiras, Cidade Ocidental, Cristalina, Formosa, Luziânia, Novo Gama, Padre Bernardo, Planaltina, Santo Antônio do Descoberto, Valparaíso de Goiás and Vila Boa), so its `stateCode` is `'DF'` even though the Distrito Federal holds only one of its thirteen municipalities, Brasília. The other three are 42, shared by Paraná and Porto União (SC), 47, shared by Santa Catarina and Rio Negro (PR), and 49, shared by Santa Catarina and Barracão (PR), and there the seat does hold every municipality but the one named.
+- 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.
```javascript
import { getAreaCodeInfo } from '@brazilian-utils/brazilian-utils';
@@ -562,11 +722,14 @@ getAreaCodeInfo(-11); // null
getAreaCodeInfo(1.1); // null
```
+Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Anatel Códigos Nacionais](https://www.gov.br/anatel/pt-br/regulado/numeracao/codigos-nacionais).
+
### getAreaCodesByState
Get every DDD (area code) that serves a given Brazilian state, under the Anatel Plano Geral de Numeração. The match is case-insensitive and the result is sorted in ascending order.
-A DDD that straddles a state border is listed under every state it serves, so DDD 61 comes back for both `'DF'` and `'GO'`: it serves the Distrito Federal and the twelve Goiás municipalities of the Entorno do Distrito Federal. The other three are 42, shared by Paraná and Porto União (SC), 47, shared by Santa Catarina and Rio Negro (PR), and 49, shared by Santa Catarina and Barracão (PR).
+- Returns `[]` when `stateCode` does not match a Brazilian state.
+- A DDD that straddles a border (the same four as `getAreaCodeInfo`) is listed under every state it serves.
```javascript
import { getAreaCodesByState } from '@brazilian-utils/brazilian-utils';
@@ -579,11 +742,13 @@ getAreaCodesByState('SC'); // [42, 47, 48, 49]
getAreaCodesByState('XX'); // []
```
+Source: [Resolução Anatel nº 749/2022](https://informacoes.anatel.gov.br/legislacao/resolucoes/2022/1641-resolucao-749), [Anatel Códigos Nacionais](https://www.gov.br/anatel/pt-br/regulado/numeracao/codigos-nacionais).
+
## License plate
### isValidLicensePlate
-Check if license plate is valid. Supports the old Brazilian format (ABC-1234) and the Mercosul format (ABC1D23), the single sequence Resolução CONTRAN nº 969/2022 defines for every vehicle, motorcycles included.
+Check if a license plate is valid. Accepts the old Brazilian format (`ABC-1234`) and the Mercosul format (`ABC1D23`), with or without a hyphen or space, in any case.
```javascript
import { isValidLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -596,9 +761,13 @@ isValidLicensePlate('ABC12D3'); // false (not a Mercosul sequence)
isValidLicensePlate('ABC1234EXTRA'); // false (too many characters)
```
+Source: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf), [Anexos](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022anexos.pdf).
+
### formatLicensePlate
-Format a license plate. Old Brazilian plates (`LLLNNNN`) are returned with a hyphen and Mercosul plates (`LLLNLNN`) stay normalized. Partial values are formatted as far as they go, so it can also be used as an input mask, and a value that cannot start a valid plate gives `''`.
+Format a license plate. Old Brazilian plates (`LLLNNNN`) get a hyphen; Mercosul plates (`LLLNLNN`) are returned without a separator.
+
+- Returns `''` when the value cannot start a valid plate.
```javascript
import { formatLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -619,7 +788,9 @@ parseLicensePlate('abc-1234'); // 'ABC1234'
### generateLicensePlate
-Generate a random license plate in the chosen format. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random license plate in the chosen format.
+
+- `format` (`GenerateLicensePlateFormat`): `'LLLNLNN'` (Mercosul, the default) or `'LLLNNNN'` (the old Brazilian format). Any other value falls back to the default.
```javascript
import { generateLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -629,11 +800,14 @@ generateLicensePlate('LLLNNNN'); // 'ABC1234'
generateLicensePlate('LLLNNLN'); // 'ABC1D23' (a format outside the two in circulation falls back to the default)
```
-A `format` outside the two supported literals falls back to the Mercosul default, the way every other generator in this package treats an option it does not know, so the result is always a plate `isValidLicensePlate` accepts. That default sequence is `LLLNLNN`, from Resolução CONTRAN nº 969/2022, Anexo I item 1.2, the single sequence the resolution defines for every vehicle, motorcycles included. (2.3.0 used an unknown string verbatim, so `generateLicensePlate('LLLNNLN')` produced the withdrawn motorcycle sequence and `generateLicensePlate('bogus')` five digits; neither is a plate.)
+Source: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf).
### getFormatLicensePlate
-Detect the normalized format of a license plate.
+Detect the normalized format of a license plate: `'LLLNNNN'` for the old Brazilian format, `'LLLNLNN'` for Mercosul.
+
+- Returns `null` when the value, separators removed, is not 7 letters and digits in one of the two formats.
+- Exports the `LicensePlateFormat` type, which `generateLicensePlate` re-exports as `GenerateLicensePlateFormat`.
```javascript
import { getFormatLicensePlate } from '@brazilian-utils/brazilian-utils';
@@ -645,11 +819,11 @@ getFormatLicensePlate('INVALID'); // null
getFormatLicensePlate('ABC1234EXTRA'); // null (too many characters)
```
-`getFormatLicensePlate` exports the `LicensePlateFormat` type (`"LLLNNNN" | "LLLNLNN"`); `generateLicensePlate` re-exports it as `GenerateLicensePlateFormat`.
-
### convertLicensePlateToMercosul
-Convert an old format Brazilian license plate (`LLLNNNN`) to the Mercosul format (`LLLNLNN`), following the official conversion table: the digit in the 5th position becomes a letter (`0` through `9` mapping to `A` through `J`). Returns `""` when the value is not a valid old format license plate.
+Convert an old format Brazilian license plate (`LLLNNNN`) to the Mercosul format (`LLLNLNN`). The 5th digit becomes a letter, `0` through `9` mapping to `A` through `J`.
+
+- Returns `""` when the value is not a valid old format license plate.
```javascript
import { convertLicensePlateToMercosul } from '@brazilian-utils/brazilian-utils';
@@ -659,11 +833,15 @@ convertLicensePlateToMercosul('abc-1234'); // 'ABC1C34'
convertLicensePlateToMercosul('ABC1D23'); // '' (already Mercosul)
```
+Source: [Resolução CONTRAN nº 969/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022.pdf), [Anexo II](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9692022anexos.pdf).
+
## RENAVAM
### isValidRenavam
-Check if RENAVAM (Registro Nacional de Veículos Automotores) is valid. Supports both the old format (9 digits) and the new format (11 digits). Any spaces, dots and hyphens around/between the digits are ignored, but any other character, a letter in particular, makes the value invalid. A registration whose digits are all the same is rejected as well.
+Check if a RENAVAM (Registro Nacional de Veículos Automotores) is valid. Accepts the old format (9 digits) and the new format (11 digits).
+
+- Spaces, dots and hyphens are ignored; any other character makes the value invalid.
```javascript
import { isValidRenavam } from '@brazilian-utils/brazilian-utils';
@@ -678,7 +856,7 @@ isValidRenavam('ab00639884962'); // false (letters are rejected)
### generateRenavam
-Generate a valid random RENAVAM: the 11 digit form, ten base digits plus the check digit. A base whose digits are all the same is drawn again, since `isValidRenavam` rejects those. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random RENAVAM in the 11 digit form: ten base digits plus the check digit.
```javascript
import { generateRenavam } from '@brazilian-utils/brazilian-utils';
@@ -690,17 +868,22 @@ generateRenavam(); // '12345678900'
### isValidPis
-Check if PIS is valid. Accepts the usual mask characters (`.`, `-`, `/`, `(`, `)`, `,`, `*`) and whitespace.
+Check if a PIS is valid. Accepts the value masked or not.
+
+- A value whose digits are all the same is rejected.
```javascript
import { isValidPis } from '@brazilian-utils/brazilian-utils';
+isValidPis('12056412847'); // true
isValidPis('12056412547'); // false
```
### formatPis
-Format PIS number. `options.pad` (part of `FormatPisOptions`) left-pads the value with zeros to the full 11 digits before masking (default `false`).
+Format a PIS.
+
+- **Options** (`FormatPisOptions`): `pad` left-pads the value with zeros to 11 digits before masking (default `false`).
```javascript
import { formatPis } from '@brazilian-utils/brazilian-utils';
@@ -721,7 +904,7 @@ parsePis('123.45678.90-1'); // 12345678901
### generatePis
-Generate a valid random PIS. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random PIS.
```javascript
import { generatePis } from '@brazilian-utils/brazilian-utils';
@@ -733,7 +916,10 @@ generatePis(); // '91077906857'
### isValidProcessoJuridico
-Validate the processo jurídico number according to [CNJ's definition](https://atos.cnj.jus.br/atos/detalhar/119): the `NNNNNNN-DD.AAAA.J.TR.OOOO` layout, the `DD` check digits and the `J`/`TR` pair, which must identify an existing órgão and tribunal from the closed lists defined by Resolução CNJ nº 65/2008, so a number carrying a correct check digit but a court that does not exist is rejected. The closed lists come from art. 1º, § 4º and § 5º of the resolution, § 5º, III in the wording Resolução CNJ nº 477/2022 gave it to seat the TRF da 6ª Região. The unidade de origem (`OOOO`) is only read as four digits, since art. 1º, § 6º leaves its codification to each tribunal and publishes no central list. The CNJ mask separators (whitespace, `.` and `-`) are accepted between the fields, and whitespace around the value is ignored, but any other character, a letter in particular, makes the value invalid.
+Check if a processo jurídico number is valid, per Resolução CNJ nº 65/2008. Three things are checked: the `NNNNNNN-DD.AAAA.J.TR.OOOO` layout, the `DD` check digits (ISO 7064 MOD 97-10) and the `J`/`TR` pair.
+
+- `J` and `TR` must name an órgão and a tribunal that exist.
+- The unidade de origem (`OOOO`) is only checked as four digits.
```javascript
import { isValidProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -745,9 +931,13 @@ isValidProcessoJuridico('0000100-23.2008.8.28.0000'); // false (no 28th Tribunal
isValidProcessoJuridico('ab00020802520125150049'); // false (letters are rejected)
```
+Source: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
### formatProcessoJuridico
-Format the processo jurídico number according to [CNJ's definition](https://atos.cnj.jus.br/atos/detalhar/119) (mask `NNNNNNN-DD.AAAA.J.TR.OOOO`). `options.pad` (part of `FormatProcessoJuridicoOptions`) left-pads the value with zeros to the full 20 digits before masking (default `false`).
+Format a processo jurídico number in the CNJ mask `NNNNNNN-DD.AAAA.J.TR.OOOO`.
+
+- **Options** (`FormatProcessoJuridicoOptions`): `pad` left-pads the value with zeros to 20 digits before masking (default `false`).
```javascript
import { formatProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -756,9 +946,11 @@ formatProcessoJuridico('00020802520125150049'); // 0002080-25.2012.5.15.0049
formatProcessoJuridico('20802520125150049', { pad: true }); // 0002080-25.2012.5.15.0049
```
+Source: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
### parseProcessoJuridico
-Remove processo jurídico formatting, keep only digits, and cap the result to 20 digits. Both the current CNJ mask (`NNNNNNN-DD.AAAA.J.TR.OOOO`) and the older one are accepted, since only the digits are kept.
+Remove processo jurídico formatting, keep only digits, and cap the result to 20 digits.
```javascript
import { parseProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -768,7 +960,11 @@ parseProcessoJuridico('0002080-25.2012.5.15.0049'); // 00020802520125150049
### generateProcessoJuridico
-Generate a valid random processo jurídico number according to [CNJ's definition](https://atos.cnj.jus.br/atos/detalhar/119). `year` must be between the current year and 9999, `court` between 1 and 9; out-of-range values return `null`. The órgão (`J`) and the tribunal (`TR`) are drawn from the closed lists of art. 1º, § 4º and § 5º, so the pair always names a court that exists: `court` picks the órgão and the `TR` is drawn among the tribunais that órgão has. The unidade de origem (`OOOO`) is drawn freely, since the resolution publishes no central list for it. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random processo jurídico number in the layout of Resolução CNJ nº 65/2008.
+
+- **Options** (`GenerateProcessoJuridicoParams`): `year` sets the `AAAA` field, an integer from the current year to 9999 (default: the current year); `court` sets the órgão `J`, from 1 to 9 (default: random).
+- `TR` is drawn among the tribunais of the chosen órgão, so the pair always names a court that exists.
+- Returns `null` when `year` or `court` is out of range.
```javascript
import { generateProcessoJuridico } from '@brazilian-utils/brazilian-utils';
@@ -779,11 +975,16 @@ generateProcessoJuridico({ year: 10000 }); // null (year out of range)
generateProcessoJuridico({ court: 10 }); // null (no such órgão)
```
+Source: [Resolução CNJ nº 65/2008](https://atos.cnj.jus.br/atos/detalhar/119).
+
## Bank accounts and banks
### isValidBankAccount
-Check if a Brazilian bank account is valid. The `bankCode` must belong to the Banco Central do Brasil STR participants list (the same dataset used by `getBankByCode`), so an unassigned code such as `'999'` is always invalid. Banks are then validated in one of three ways: by their published check digit algorithm, by structure only (bank exists and the agency/account match the documented digit lengths, for banks that publish no check digit rule) or by a generic mod10/mod11 check, which stays the fallback for every other listed bank.
+Check if a Brazilian bank account is valid. The `bankCode` must be a Banco Central STR participant (the list `getBankByCode` uses).
+
+- **Params** (`IsValidBankAccountParams`, all strings): `bankCode` (3 digits), `agency` (1-5 digits), `account` (1-13 digits) and `digit` (1-2 characters, or `X` for Banco do Brasil and `P` for Bradesco).
+- A listed bank is validated in one of three ways: by its published check digit algorithm, by structure only, or by a generic mod10/mod11 fallback.
Banks validated by their published check digit algorithm:
@@ -799,7 +1000,7 @@ Banks validated by their published check digit algorithm:
| HSBC / Kirton Bank | `399` | 4 digits | 6 digits | weights `8,9,2,3,4,5,6,7,8,9` over agency + account; remainder 10 gives `0` |
| Citibank | `745` | 4 digits | 10 digits | weights `11..2` over the account; remainder 0 or 1 gives `0` |
-Banks validated by structure only, because they publish no check digit rule. The agency (1-5 digits), the account (1-13 digits) and a single numeric `digit` are enough to make the account valid:
+Banks validated by structure only (a single numeric `digit` is enough):
| Bank | Code | | Bank | Code |
| --- | --- | --- | --- | --- |
@@ -813,9 +1014,7 @@ Banks validated by structure only, because they publish no check digit rule. The
| PagBank | `290` | | Sicredi | `748` |
| BMG | `318` | | Sicoob | `756` |
-When `digit` has 2 characters, the generic fallback chains mod10 followed by mod11 over the account, the same way CPF/CNPJ check digits are chained.
-
-Sources: the "Regras de Validação de dígito verificador de agência e conta corrente" compendium, cross checked against `banktools-br` (Ruby), `luizalabs/heimdall` (Python) and `Xerpa/bran_checker` (Elixir). Each shipped algorithm agrees on at least two independent sources.
+- Every other listed bank uses the generic fallback: `digit` must match mod10 or mod11 over the account. A 2 character `digit` chains mod10 then mod11.
```javascript
import { isValidBankAccount } from '@brazilian-utils/brazilian-utils';
@@ -884,9 +1083,13 @@ isValidBankAccount({
}); // true (Banco ABC Brasil, generic mod10 fallback)
```
+Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv), [Regras de Validação de dígito verificador](https://github.com/eduardokum/laravel-boleto/blob/master/manuais/Regras%20Validacao%20Conta%20Corrente%20VI_EPS.pdf).
+
### getBanks
-Get every Brazilian bank with a compensation code (COMPE), published by Banco Central do Brasil in the [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Each bank (typed as `Bank`) has a `code` (COMPE, 3 digits), an `ispb` (Identificador do Sistema de Pagamentos Brasileiro, 8 digits) and a `name`. Each call returns a fresh array of fresh objects, so mutating the result never affects subsequent calls.
+Get every Brazilian bank with a compensation code (COMPE), from the Banco Central do Brasil STR participants list.
+
+- Each bank (`Bank`) has a `code` (COMPE, 3 digits), an `ispb` (8 digits) and a `name`.
```javascript
import { getBanks } from '@brazilian-utils/brazilian-utils';
@@ -900,9 +1103,13 @@ getBanks();
// ]
```
+Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv).
+
### getBankByCode
-Look a Brazilian bank up by its compensation code (COMPE), published by Banco Central do Brasil in the [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Accepts both `string` and `number` input, with or without leading zeros. Returns a fresh copy (typed as `Bank`) of the matching bank, or `null` when no bank has that code.
+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`.
+
+- Returns the matching `Bank`, or `null` when no bank has that code.
```javascript
import { getBankByCode } from '@brazilian-utils/brazilian-utils';
@@ -912,9 +1119,13 @@ getBankByCode(1); // { code: '001', ispb: '00000000', name: 'Banco do Brasil S.A
getBankByCode('999'); // null
```
+Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv).
+
### getBankByIspb
-Look a Brazilian bank up by its ISPB (Identificador do Sistema de Pagamentos Brasileiro), the 8 digit code published by Banco Central do Brasil in the [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv). Every SPB participant has an ISPB, but this dataset only carries the institutions that also have a COMPE code, so an ISPB whose institution has no COMPE code of its own returns `null`. Accepts both `string` and `number` input, with or without leading zeros, so `getBankByIspb(0)` finds the same bank as `getBankByIspb('00000000')`. The dataset is generated from that CSV, falling back to [BrasilAPI](https://brasilapi.com.br/api/banks/v1) when the Bacen request fails. Returns a fresh copy (typed as `Bank`) of the matching bank, or `null` when no bank has that ISPB.
+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.
+
+- Returns the matching `Bank`, or `null` when no bank has that ISPB. The base only carries institutions that also have a COMPE code.
```javascript
import { getBankByIspb } from '@brazilian-utils/brazilian-utils';
@@ -924,11 +1135,17 @@ getBankByIspb('60701190'); // { code: '341', ispb: '60701190', name: 'ITAÚ UNIB
getBankByIspb('99999999'); // null
```
+Source: [STR participants list](https://www.bcb.gov.br/content/estabilidadefinanceira/str1/ParticipantesSTR.csv), [BrasilAPI](https://brasilapi.com.br/api/banks/v1).
+
## IBAN
### isValidIban
-Check if a Brazilian IBAN (International Bank Account Number) is valid, per Bacen's [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf) (Circular BCB nº 3.625/2013): `BR` + 2 ISO 7064 MOD 97-10 check digits + 8 digit ISPB + 5 digit branch + 10 digit account + 1 letter account type (any letter, usually `C` for conta corrente or `P` for conta poupança) + 1 owner indicator (`1` for the first or only holder up to `9` for the ninth, then `A` to `Z` from the tenth, so `0` is rejected), 29 characters total. Only Brazilian IBANs (country code `BR`) are recognized; any other country returns `false`, since this package does not carry the field layout of the other 90+ ISO 13616 countries. Is case-insensitive and accepts both forms an IBAN is written in: compact (`'BR1500000000000010932840814P2'`) or in the ISO 13616 print format, letters and digits in groups of 4 (the last one shorter), with optional surrounding whitespace either way. The groups may be split by whitespace, `.`, `-` or `/`, the interchangeable mask characters `isValidCpf` and `isValidCnpj` accept. Only a separator away from a group boundary, a run of separators (ISO 13616 prints a single one) or a character outside letters and digits makes the value something other than an IBAN, so it is rejected instead of being stripped.
+Check if a Brazilian IBAN (International Bank Account Number) is valid. Only Brazilian IBANs (country code `BR`) are recognized; any other country returns `false`.
+
+- Layout, 29 characters: `BR`, 2 check digits (ISO 7064 MOD 97-10), 8 digit ISPB, 5 digit branch, 10 digit account, 1 letter account type, 1 owner indicator.
+- Account type: any letter, usually `C` or `P`. Owner: `1` to `9`, then `A` to `Z`.
+- Accepts the compact form or groups of 4 split by one whitespace, `.`, `-` or `/`, in any case.
```javascript
import { isValidIban } from '@brazilian-utils/brazilian-utils';
@@ -941,9 +1158,13 @@ isValidIban('BR15 000 00000 0000 1093 2840 814P 2'); // false (a separator insid
isValidIban('DE89370400440532013000'); // false (non Brazilian IBAN)
```
+Source: [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf), [Circular BCB nº 3.625/2013](https://www.bcb.gov.br/pre/normativos/circ/2013/pdf/circ_3625_v1_O.pdf), [ISO 13616-1:2020](https://www.iso.org/standard/81090.html).
+
### formatIban
-Format an IBAN in the ISO 13616 print grouping, blocks of 4 characters, the presentation used on statements and bank forms. Does not validate the check digits or the field layout; formats whatever is given, up to the 29 character length of a Brazilian IBAN, as far as it goes, so the function can also be used as an input mask, and an IBAN of another country is grouped the same way up to that length. Use `isValidIban` to check validity. The value may be compact (`'BR1500000000000010932840814P2'`), already in the ISO 13616 print format or a partial value still being typed (`'BR15'`); like every formatter of this package, it is read for its letters and digits and grouped as far as they go, any other character (a hyphen, a dot, extra whitespace) is dropped and the letters are uppercased. Only a value that is not a string gives an empty string.
+Format an IBAN in the ISO 13616 print grouping: blocks of 4 characters, the presentation used on statements and bank forms. Does not validate; use `isValidIban` for that.
+
+- Caps the result at 29 characters, the length of a Brazilian IBAN.
```javascript
import { formatIban } from '@brazilian-utils/brazilian-utils';
@@ -956,7 +1177,7 @@ formatIban('BR15 0000-0000.0000/1093 2840 814P-2'); // 'BR15 0000 0000 0000 1093
### parseIban
-Remove IBAN formatting, keep the letters and digits, uppercase the result, and cap it to the 29 characters of a Brazilian IBAN. An IBAN carries letters as well as digits, so the value is read the way `parsePassport` reads a passport number; use `isValidIban` to check the check digits and `getIbanInfo` to read the fields.
+Remove IBAN formatting, keep the letters and digits, uppercase the result, and cap it to the 29 characters of a Brazilian IBAN.
```javascript
import { parseIban } from '@brazilian-utils/brazilian-utils';
@@ -967,7 +1188,10 @@ parseIban('br15-0000.0000/0000 1093 2840 814p-2'); // 'BR15000000000000109328408
### getIbanInfo
-Parses a Brazilian IBAN into its fields: 2 (country code, always `BR`) + 2 (ISO 7064 MOD 97-10 check digits) + 8 (ISPB) + 5 (branch) + 10 (account) + 1 (account type, any letter, usually `C` for conta corrente or `P` for conta poupança) + 1 (owner indicator, `1` to `9` then `A` to `Z`). Only Brazilian IBANs are supported: the field layout of the other ISO 13616 countries is out of scope, so a well-formed non `BR` IBAN also returns `null`. Accepts the same input forms as `isValidIban`, compact or in the ISO 13616 print format (groups of 4 split by a single whitespace, `.`, `-` or `/`), in either case with optional surrounding whitespace and in any case, and returns `null` whenever `isValidIban` would return `false`, including a value carrying a separator away from a group boundary, a run of separators or any character other than letters and digits. The result is typed as `IbanInfo`, whose `accountType` is a `string`.
+Parse a Brazilian IBAN into its fields. Returns an `IbanInfo` object, or `null` whenever `isValidIban` would return `false`.
+
+- Fields, all strings: `countryCode`, `checkDigits`, `bankIspb`, `branch`, `account`, `accountType` (usually `C` or `P`) and `owner` (`1` to `9`, then `A` to `Z`).
+- Same input rules as `isValidIban`.
```javascript
import { getIbanInfo } from '@brazilian-utils/brazilian-utils';
@@ -987,11 +1211,17 @@ getIbanInfo('DE89370400440532013000'); // null (non Brazilian IBAN)
getIbanInfo('BR15 000 00000 0000 1093 2840 814P 2'); // null (a separator inside a group)
```
+Source: [Diretrizes de Implementação do IBAN no Brasil](https://www.bcb.gov.br/content/estabilidadefinanceira/Documents/sistema_pagamentos_brasileiro/IBAN-Guidelines_%20port.pdf), [Circular BCB nº 3.625/2013](https://www.bcb.gov.br/pre/normativos/circ/2013/pdf/circ_3625_v1_O.pdf), [ISO 13616-1:2020](https://www.iso.org/standard/81090.html).
+
## Currency, numbers and dates in words
### formatCurrency
-Formats an integer or float to a string in the BRL pattern. A `number` is formatted as-is (sign and decimals preserved). A `string` input is read by the same rule as `parseCurrency`, except that a value written without any separator stays in whole units: the last `,` or `.` followed by 1 to 2 digits (or up to `precision` digits, when that is larger) is the decimal separator, every other `,` or `.` is a thousands separator, and a `-` written before the first digit is preserved. So `'1.234,56'` formats as `1.234,56`, `'-10.5'` as `-10,50` and `'1234'` as `1.234,00`. `precision` is clamped to `0..20` (the package limit, the bound Node 20 still enforces on `Intl.NumberFormat`), defaults to 2, and falls back to 2 when it is not a finite number. A value that is not a finite number (`NaN`, `Infinity`, `-Infinity`) formats as an empty string, and so does a value that cannot be coerced to a number (a symbol, a plain object, a null-prototype object); `null`, arrays and booleans go through `Number()` as in 2.3.0. `options.symbol` prefixes the result with the `R$` currency symbol (default `false`). Options are typed as `FormatCurrencyOptions`.
+Format a number or a numeric string in the BRL pattern (`1.234,56`). A `number` is formatted as is, sign and decimals preserved.
+
+- **Options** (`FormatCurrencyOptions`): `symbol` (default `false`) prefixes the result with `R$`; `precision` (default 2) sets the decimal places, clamped to 0 to 20.
+- A `string` is read as `parseCurrency` reads it, except that a value without any separator stays in whole units: `'1234'` formats as `1.234,00`.
+- Returns `''` for a non-finite value or one that cannot be coerced to a number.
```javascript
import { formatCurrency } from '@brazilian-utils/brazilian-utils';
@@ -1009,7 +1239,11 @@ formatCurrency(Number.NaN); // "" (non finite numbers format as an empty string)
### parseCurrency
-Transforms a string to an integer or float format. The last `,` or `.` followed by 1 to 2 digits (or up to `precision` digits, when that is larger) is the decimal separator; every other `,` or `.` is a thousands separator. So `'R$ 1.234,56'` parses to `1234.56`, `'R$ 1.234'` to `1234`, `'1,5'` to `1.5` and `'12.34'` to `12.34`. A value written without any separator keeps the cents convention and is divided by `10 ** precision`, so `'1234'` parses to `12.34`. A `-` written before the first digit is preserved, so `'-R$ 1,00'` parses to `-1`. `precision` (default 2, clamped to `0..20`, and falling back to 2 when it is not a finite number) controls how many digits are treated as minor units. Options are typed as `ParseCurrencyOptions`.
+Parse a BRL currency string into a number.
+
+- **Options** (`ParseCurrencyOptions`): `precision` (default 2) is the number of digits read as minor units, clamped to 0 to 20.
+- The last `,` or `.` followed by 1 to 2 digits (up to `precision`, when larger) is the decimal separator; every other `,` or `.` is a thousands separator.
+- A value without any separator is read as cents and divided by `10 ** precision`.
```javascript
import { parseCurrency } from '@brazilian-utils/brazilian-utils';
@@ -1027,7 +1261,11 @@ parseCurrency(''); // 0
### convertNumberToWords
-Formats an integer as its Brazilian Portuguese cardinal number words ("por extenso"), e.g. `1235` becomes `"mil duzentos e trinta e cinco"`. Only integers from `-999999999999999` to `999999999999999` (999 trillion in absolute value) are supported; anything outside that range, `NaN` or a non-finite value returns `""`. A non-integer `value` is truncated toward zero before conversion. `options.gender` (part of `ConvertNumberToWordsOptions`) agrees "um/dois" and the hundreds group ("duzentos/duzentas", etc.) with the noun the number qualifies, defaulting to `"masculine"`. An invalid `gender` value is ignored and the default is used. The result is always lowercase; apply any other casing to it yourself.
+Write an integer in Brazilian Portuguese cardinal words ("por extenso"): `1235` becomes `"mil duzentos e trinta e cinco"`.
+
+- **Options** (`ConvertNumberToWordsOptions`): `gender` (default `"masculine"`) agrees "um/dois" and the hundreds ("duzentos/duzentas") with the noun the number qualifies.
+- Accepts integers from `-999999999999999` to `999999999999999` (999 trillion). A non-integer is truncated toward zero.
+- Returns `""` for a value outside that range or not finite.
```javascript
import { convertNumberToWords } from '@brazilian-utils/brazilian-utils';
@@ -1043,7 +1281,10 @@ convertNumberToWords(NaN); // ""
### convertCurrencyToWords
-Formats a monetary amount in Brazilian Reais as its "por extenso" textual representation, the style used to write out the amount by hand on cheques and contracts, e.g. `1523.45` becomes `"mil quinhentos e vinte e três reais e quarenta e cinco centavos"`. `value` is truncated (not rounded) to 2 decimal places. The singular noun is used for exactly 1 ("um real", "um centavo") and "de" is inserted before "reais" when the amount is a round million, billion or trillion of reais. An amount that truncates to nothing becomes `"zero reais"` with no "menos" prefix, any other negative amount is prefixed with "menos", and invalid input returns `""`. Above `Number.MAX_SAFE_INTEGER / 100` reais (about 90 trillion) a double cannot carry cents, so the amount is read as a whole number of reais. It takes no options: the result is always lowercase; apply any other casing to it yourself.
+Write an amount in reais in words ("por extenso"), as on cheques and contracts: `1523.45` becomes `"mil quinhentos e vinte e três reais e quarenta e cinco centavos"`. Takes no options.
+
+- `value` is truncated (not rounded) to 2 decimal places.
+- Returns `""` for invalid input or an amount above 999 trillion reais.
```javascript
import { convertCurrencyToWords } from '@brazilian-utils/brazilian-utils';
@@ -1059,7 +1300,10 @@ convertCurrencyToWords(-0.001); // "zero reais" (truncates to nothing)
### convertDateToWords
-Formats a date as its Brazilian Portuguese "por extenso" textual representation, e.g. `"01/01/2024"` becomes `"primeiro de janeiro de dois mil e vinte e quatro"`. Accepts a `Date` (read by its local calendar date, the same convention used by `isHoliday`) or a string in `"dd/mm/yyyy"` or ISO `"yyyy-mm-dd"` format. With the default `options.style` of `"full"`, day 1 is written as "primeiro" and every other day uses the cardinal number; with `"month"`, only the month name is spelled out and the day/year are left as digits (day 1 as `"1º"`, e.g. `"2 de março de 2024"`, `"1º de janeiro de 2024"`). Month names are lowercase. In `"full"` style the year is written out as a cardinal number without the thousands comma that `convertNumberToWords`/`convertCurrencyToWords` use (`1999` reads as `"mil novecentos e noventa e nove"`, not `"mil novecentos e noventa e nove"`), matching how a date is read aloud. `options.weekday` (default `false`) prefixes the pt-BR weekday name in lowercase followed by a comma (`"sábado, dois de março de dois mil e vinte e quatro"`), computed from the resolved calendar date. An invalid `style` value is ignored and the default is used. The result is always lowercase; apply any other casing to it yourself. February 29th is accepted on the leap years of the proleptic Gregorian calendar (divisible by 4, except centuries not divisible by 400). Returns `""` for an invalid `Date`, a malformed string, a day/month that does not exist, or a date before year 1.
+Write a date in Brazilian Portuguese words ("por extenso"): `"01/01/2024"` becomes `"primeiro de janeiro de dois mil e vinte e quatro"`. Accepts a `Date`, read by its local calendar date, or a string in `"dd/mm/yyyy"` or ISO `"yyyy-mm-dd"` format.
+
+- **Options** (`ConvertDateToWordsOptions`): `style` (default `"full"`) spells out day, month and year; `"month"` spells out only the month and leaves day and year as digits, day 1 as `"1º"`. `weekday` (default `false`) prefixes the lowercase weekday name and a comma.
+- Returns `""` for an invalid `Date`, a malformed string, a day or month that does not exist, or a date before year 1.
```javascript
import { convertDateToWords } from '@brazilian-utils/brazilian-utils';
@@ -1080,7 +1324,10 @@ convertDateToWords('29/02/1900'); // "" (1900 is not a leap year)
### getStates
-Get all Brazilian states, each with its two-letter code, name, region code, region name and 2-digit IBGE code of the Federative Unit (`cUF`). The list is sorted by name with `localeCompare` in the "pt-BR" locale, so accented names land where a Brazilian reader expects them: Pará, Paraíba, Paraná and Rio de Janeiro, Rio Grande do Norte, Rio Grande do Sul. Each call returns a fresh array of fresh objects, so mutating the result never affects subsequent calls. Exports the `State`, `StateCode` and `StateName` types. `State` is a discriminated union with one member per state, so the fields of a state are tied to each other: narrowing a `State` by `code` narrows its `name`, `regionCode`, `regionName` and `ibgeCode` too (`Extract['name']` is `'São Paulo'`), and an impossible combination such as `{ code: 'SP', name: 'Acre' }` is not a `State`.
+Get all Brazilian states, each with its two-letter code, name, region code, region name and 2-digit IBGE code (`cUF`).
+
+- Sorted by name in the "pt-BR" locale.
+- Exports the `State`, `StateCode` and `StateName` types. `State` is a discriminated union: narrowing it by `code` also narrows the other fields.
```javascript
import { getStates } from '@brazilian-utils/brazilian-utils';
@@ -1117,9 +1364,15 @@ getStates();
// ]
```
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
### getStateByIbgeCode
-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 same 2-digit UF code found in the first field of every DF-e access key (chave de acesso) issued for any of the models `isValidNfeKey` covers: NF-e (55), NFC-e (65), CT-e (57), MDF-e (58), CT-e OS (67), GTV-e (64), BP-e (63), NF3e (66) and NFCom (62). Accepts a string or a non-negative integer number, stripping any non-digit characters before matching. Exports the `State` type.
+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.
+- Returns `null` when the code matches no state. Exports the `State` type.
```javascript
import { getStateByIbgeCode } from '@brazilian-utils/brazilian-utils';
@@ -1135,9 +1388,14 @@ getStateByIbgeCode(-35); // null
getStateByIbgeCode(3.5); // null
```
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/v1/localidades/estados), [Manual de Orientação do Contribuinte](https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-visao-geral.pdf)
+
### getStateCodeByName
-Get the two-letter code (sigla) of a Brazilian state given its full name. The match is accent-insensitive, case-insensitive and ignores leading/trailing whitespace, so `'sao paulo'`, `'SÃO PAULO'` and `' São Paulo '` all resolve to `'SP'`. Every run of internal whitespace collapses into a single space too, so `'Rio de Janeiro'` resolves to `'RJ'`, while a name written without the space matches nothing (`'saopaulo'` is not `'São Paulo'`). Exports the `StateCode` type.
+Get the two-letter code (sigla) of a Brazilian state from its full name.
+
+- The match ignores accents, case and surrounding whitespace; internal whitespace collapses into one space.
+- Returns `null` when no state matches. Exports the `StateCode` type.
```javascript
import { getStateCodeByName } from '@brazilian-utils/brazilian-utils';
@@ -1150,7 +1408,10 @@ getStateCodeByName('Neverland'); // null
### getStateNameByCode
-Get the full name of a Brazilian state given its two-letter code (sigla). The match is case-insensitive and ignores leading/trailing whitespace, so `'sp'`, `'SP'` and `' Sp '` all resolve to `'São Paulo'`. Exports the `StateName` type.
+Get the full name of a Brazilian state from its two-letter code (sigla).
+
+- The match ignores case and surrounding whitespace.
+- Returns `null` when no state matches. Exports the `StateName` type.
```javascript
import { getStateNameByCode } from '@brazilian-utils/brazilian-utils';
@@ -1163,7 +1424,10 @@ getStateNameByCode('ZZ'); // null
### getTimezoneByState
-Get the IANA time zone database name (tzdata zone) for a Brazilian state, chosen as the zone of the state capital. The match is case-insensitive and ignores leading/trailing whitespace. Some tzdata zones cover more than one state: `America/Sao_Paulo` also covers DF, GO, MG, ES, RJ, PR, SC and RS besides SP, and `America/Fortaleza` also covers MA, PI, RN and PB besides CE. Pernambuco resolves to `America/Recife`, not `America/Noronha`: Fernando de Noronha is an archipelago district of PE, not a state of its own.
+Get the IANA time zone name (tzdata zone) of a Brazilian state: the zone of its capital.
+
+- The match ignores case and surrounding whitespace.
+- Returns `null` when no state matches.
```javascript
import { getTimezoneByState } from '@brazilian-utils/brazilian-utils';
@@ -1175,9 +1439,16 @@ getTimezoneByState('PE'); // 'America/Recife'
getTimezoneByState('ZZ'); // null
```
+Source: [IANA Time Zone Database](https://www.iana.org/time-zones)
+
### getMunicipalities
-Get Brazilian municipalities published by the IBGE. Returns all municipalities if no state is provided, or municipalities from a specific state. Each municipality is returned as `{ code, name, stateCode }`, where `code` is the 7-digit IBGE municipality code. Results are sorted by name with `localeCompare` in the "pt-BR" locale. Each call returns a fresh array of fresh objects, so mutating the result never affects subsequent calls. An unknown state code returns an empty array instead of throwing. Only an omitted (or `undefined`) `stateCode` asks for the full list: `getMunicipalities(null)` and `getMunicipalities('')` return `[]`, where the looser `getCities(null)` and `getCities('')` return every city. The state code is matched exactly, case included: `getMunicipalities('sp')` returns `[]` where `getMunicipalities('SP')` returns the 645 São Paulo municipalities. `getMunicipalities` and `getCities` are the only state-taking lookups that are case-sensitive; `getStateNameByCode`, `getTimezoneByState`, `getAreaCodesByState` and `getMunicipality` all fold case.
+Get the Brazilian municipalities published by the IBGE: every municipality, or only those of one state when `stateCode` is given.
+
+- Each municipality (`Municipality`) is `{ code, name, stateCode }`, where `code` is the 7-digit IBGE code. Sorted by name in the "pt-BR" locale.
+- Only an omitted (or `undefined`) `stateCode` asks for the full list: `null` and `''` return `[]`.
+- `stateCode` is case-sensitive: `'sp'`, like an unknown code, returns `[]`.
+- Embeds all 5571 municipalities. See [Bundle size](getting-started.md#bundle-size) to lazy-load it via `@brazilian-utils/brazilian-utils/get-municipalities`.
```javascript
import { getMunicipalities } from '@brazilian-utils/brazilian-utils';
@@ -1207,11 +1478,14 @@ getMunicipalities('SP');
getMunicipalities('ZZ'); // []
```
-`getMunicipalities` embeds all 5571 IBGE municipalities and their codes, so it carries the same bundle-size cost as `getCities`. See [Bundle size](getting-started.md#bundle-size) for how to lazy-load it via `@brazilian-utils/brazilian-utils/get-municipalities` instead of the root import.
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
### getMunicipalityByCode
-Look up a Brazilian municipality by its 7-digit IBGE code. Accepts the code as a string or a number, with any non-digit characters stripped before matching; a code given as a number must be a non-negative integer, so `-3550308` and `355030.8` return `null` instead of being read as `3550308`. Returns `{ code, name, stateCode }`, a fresh object, or `null` when the code is not 7 digits long or does not match any known municipality.
+Look up a Brazilian municipality by its 7-digit IBGE code.
+
+- Accepts the code as a string or a non-negative integer.
+- Returns `{ code, name, stateCode }` (`Municipality`), or `null` when the code is not 7 digits long or matches no municipality.
```javascript
import { getMunicipalityByCode } from '@brazilian-utils/brazilian-utils';
@@ -1226,9 +1500,16 @@ getMunicipalityByCode('0000000'); // null (unknown code)
getMunicipalityByCode('123'); // null (not 7 digits)
```
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
### getCities
-Get Brazilian cities. **Deprecated:** use `getMunicipalities` instead. Returns all cities if no state is provided, or cities from a specific state. Each call returns a fresh array, so mutating the result never affects subsequent calls. An unknown state code (or a non-`StateCode` value) returns an empty array instead of throwing, except for a falsy one: `getCities(null)` and `getCities('')` are read as "no state given" and return every city, where the stricter `getMunicipalities` returns `[]` for them. The state code is matched exactly, case included: `getCities('sp')` returns `[]` where `getCities('SP')` returns the 645 São Paulo cities. `getCities` and `getMunicipalities` are the only state-taking lookups that are case-sensitive; `getStateNameByCode`, `getTimezoneByState`, `getAreaCodesByState` and `getMunicipality` all fold case.
+Get the names of Brazilian cities: every city, or only those of one state. **Deprecated:** use `getMunicipalities` instead.
+
+- Sorted in the "pt-BR" locale.
+- Any falsy `state` asks for the full list, where `getMunicipalities` returns `[]`.
+- `state` is case-sensitive: `'sp'`, like an unknown code, returns `[]`.
+- Embeds all 5571 names (~154.2 KB minified, ~49.8 KB gzipped). See [Bundle size](getting-started.md#bundle-size) to lazy-load it via `@brazilian-utils/brazilian-utils/get-cities`.
```javascript
import { getCities } from '@brazilian-utils/brazilian-utils';
@@ -1266,11 +1547,16 @@ getCities('SP');
// ]
```
-`getCities` embeds all 5571 IBGE municipality names (~154.2 KB minified, ~49.8 KB gzipped) and is one of the few heavy exceptions in this otherwise tree-shakeable package. See [Bundle size](getting-started.md#bundle-size) for how to lazy-load it via `@brazilian-utils/brazilian-utils/get-cities` instead of the root import.
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
### getMunicipality
-Get municipality information by IBGE code, or get an IBGE code from municipality name and UF. **Deprecated:** use `getMunicipalityByCode` instead, which is synchronous and offline; matching a municipality by name is up to the application, over `getMunicipalities`. A single function handles both directions, based on whether `options` has a `code` or a `municipalityName`/`uf`. `code` accepts both `string` and `number` input and must be exactly 7 digits, otherwise the function resolves to `null`. A `code` given as a number must be a non-negative integer: a sign and a decimal point are not digits, so `-3550308` and `355030.8` resolve to `null` instead of being read as `3550308`. Resolution is entirely offline, from a bundled IBGE dataset: no network request is made. The municipality name match ignores accents and casing, and every run of whitespace collapses into a single space, so `'sao paulo'` matches `'São Paulo'` while a name written without the space does not; the casing is folded to upper case, the direction Unicode expands `'ß'` to `'SS'` in, so `'Paßos'` matches `'Passos'`. An unknown municipality, an unknown UF or invalid input all resolve to `null`. The `[name, uf]` pair is a fresh array on every call, so mutating the result never affects subsequent lookups.
+Get municipality information by IBGE code, or an IBGE code from a municipality name and UF. **Deprecated:** use `getMunicipalityByCode` instead, which is synchronous and offline; matching a municipality by name is up to the application, over `getMunicipalities`.
+
+- One function handles both directions, based on whether `options` has a `code` or a `municipalityName`/`uf`. The lookup is offline: no network request is made.
+- The name match ignores accents and case, and every run of whitespace collapses into one space.
+- Resolves to `null` for an unknown municipality, an unknown UF or invalid input.
+- `GetMunicipalityOptions`, `GetMunicipalityByCodeOptions` and `GetMunicipalityByNameOptions` are deprecated aliases of the types below.
```javascript
import { getMunicipality } from '@brazilian-utils/brazilian-utils';
@@ -1291,8 +1577,6 @@ await getMunicipality({ code: '123' });
// null (not 7 digits)
```
-In TypeScript the return type follows the direction of the lookup: a `{ code }` query resolves to `[string, string] | null`, a `{ municipalityName, uf }` query resolves to `string | null`, and a query whose direction is only known at run time (a variable typed as `GetMunicipalityParams`) resolves to the union of both. The 2.3.0 names `GetMunicipalityOptions`, `GetMunicipalityByCodeOptions` and `GetMunicipalityByNameOptions` are still exported as deprecated aliases of these.
-
```typescript
import {
getMunicipality,
@@ -1314,22 +1598,19 @@ const lookUp = (options: GetMunicipalityParams) => getMunicipality(options);
// (options: GetMunicipalityParams) => Promise<[string, string] | string | null>
```
+Source: [IBGE Localidades](https://servicodados.ibge.gov.br/api/docs/localidades)
+
## Holidays and business days
### getHolidays
-Get Brazilian holidays for a given year. Returns national holidays and optionally state-specific holidays. Each holiday (typed as `Holiday`) has a `type` field (`HolidayType`: `"national"`, `"state"`, `"optional"` or `"religious"`). "Dia da Consciência Negra" (Nov 20) is a national holiday from 2024 onward (Lei nº 14.759/2023). Before that, several states still carry a state-level entry of their own on the same date, under the same `"Dia da Consciência Negra"` name in MT, RJ, AM and SP, and under `"Dia Estadual da Consciência Negra"` in AP, the name that state's own law uses. Commemorative dates that no law turns into a holiday are not listed: RN's "Dia do Rio Grande do Norte" (7 August, Lei RN nº 7.831/2000) is one, and neither is RO's "Dia dos Evangélicos" (18 June), whose law the STF struck down in ADI 3940. Results are memoized per `year`/`stateCode`, but each call still returns a fresh copy. An unknown/invalid `stateCode` is ignored, returning national holidays only; the lookup reads own properties only, so `"__proto__"`, `"constructor"` and the like are unknown state codes rather than a crash. Only the years 1900 through 2099 are supported, the range the business day utilities inherit; a year outside it returns `[]`.
-
-Only one state holiday per UF is a feriado civil under [Lei nº 9.093/1995](https://www.planalto.gov.br/ccivil_03/leis/l9093.htm), art. 1º, II, which authorises "a data magna do Estado fixada em lei estadual" in the singular; the other entries rest on ordinary state laws and are reported because they are observed in practice. Notable per-state rules:
+Get the Brazilian holidays of a year: the national ones and, with a `stateCode`, that state's holidays too. Accepts a year or `{ year, stateCode }` (`GetHolidaysParams`).
-- **SC** — [Lei SC nº 18.531/2022](http://leis.alesc.sc.gov.br/html/2022/18531_2022_lei.html) moves both state holidays, "Dia do Estado de Santa Catarina" (Aug 11) and "Dia de Santa Catarina de Alexandria" (Nov 25), to the following Sunday whenever they fall Monday to Friday, so Monday Aug 11 2025 is a business day in SC and the holiday lands on Sunday Aug 17. The two dates did not start transferring together. Aug 11 transfers from 2005 on, the year [Lei SC nº 13.408/2005](http://leis.alesc.sc.gov.br/html/2005/13408_2005_lei.html) extended the clause to it (published and in force on Jul 15 2005), and stays on Aug 11 before that. Nov 25 transfers from 1999 on, the year [Lei SC nº 11.213/1999](http://leis.alesc.sc.gov.br/html/1999/11213_1999_lei.html) first introduced the clause (published and in force on Nov 12 1999, thirteen days before that year's Nov 25), with a one-year gap: art. 3º of [Lei SC nº 12.906/2004](http://leis.alesc.sc.gov.br/html/2004/12906_2004_lei.html) revoked that law without restating the clause, so Nov 25 2004 alone stays on the statutory date until Lei SC nº 13.408/2005 reinstated the transfer. So Nov 25 1999 (a Thursday) lands on Sunday Nov 28, Nov 25 2002 (a Monday) on Sunday Dec 1, Nov 25 2004 (a Thursday) stays put, and Nov 25 2005 (a Friday) lands on Sunday Nov 27.
-- **DF** — [Lei distrital nº 72/1989](https://www.sinj.df.gov.br/sinj/Norma/18459/Lei_72_27_12_1989.html), art. 1º parágrafo único, declares Corpus Christi a feriado. With `stateCode: 'DF'` the single Corpus Christi entry comes back typed `"state"` instead of `"optional"`; it is replaced, not duplicated.
-- **GO** — [Lei GO nº 20.756/2020](https://legisla.casacivil.go.gov.br/pesquisa_legislacao/100979/lei-20756), art. 269, II, lists three feriados estaduais: Jul 26 (Fundação da Cidade de Goiás), Oct 24 (Lançamento da Pedra Fundamental de Goiânia) and Oct 28 (Dia do Servidor Público).
-- **AL** — Sep 16 is a feriado estadual from 2024 ([Lei AL nº 9.358/2024](https://sapl.al.al.leg.br/norma/3117)) and only a ponto facultativo (`"optional"`) before that.
-- **PB** — Jul 26 ("Morte de João Pessoa") is emitted up to 2015 only: [Lei PB nº 10.601/2015](https://sapl.al.pb.leg.br/norma/11988), art. 2º, revoked its basis.
-- **TO** — Mar 18 ("Autonomia do Estado do Tocantins") is emitted up to 2008 only: [Lei TO nº 2.013/2009](https://www.al.to.leg.br/arquivo/15724) rewrote the clause that declared the feriado into a commemorative provision.
-
-The statutory date is what is returned. SC's shift above is the only observance shift modelled; Acre's Tuesday-to-Thursday shift and the Goiás decrees that may move Jul 26 and Oct 28 are not.
+- Each holiday is a `Holiday` whose `type` (`HolidayType`) is `"national"`, `"state"`, `"optional"` or `"religious"`. Holidays are sorted by date.
+- "Dia da Consciência Negra", Nov 20, is national from 2024 on.
+- Per-state rules (SC's Sunday shift, DF's Corpus Christi, dates that stopped being holidays) follow each state's law; see the source for the list.
+- An unknown or non-string `stateCode` is ignored and only national holidays are returned.
+- Returns `[]` when the year is not an integer from 1900 to 2099, or when the argument is neither a number nor an object.
```javascript
import { getHolidays } from '@brazilian-utils/brazilian-utils';
@@ -1350,9 +1631,15 @@ getHolidays({ year: 2024, stateCode: 'SP' });
// Includes national holidays plus state-specific holidays (e.g., "Revolução Constitucionalista")
```
+Source: `src/get-holidays/constants.ts`, [Lei nº 662/1949](https://www.planalto.gov.br/ccivil_03/leis/l0662.htm), [Lei nº 9.093/1995](https://www.planalto.gov.br/ccivil_03/leis/l9093.htm).
+
### isHoliday
-Check if a specific date is a Brazilian holiday. The check compares `targetDate`'s local calendar date (year/month/day as read locally), not its underlying UTC instant. Returns `false` when `targetDate` is missing or not a valid `Date`. An invalid `stateCode` is treated in two different ways: a string that is not a known state code is ignored and only national holidays are considered, the same as `getHolidays`, while a `stateCode` that is present and is not a string at all (a number, `null`, an object) is rejected and makes the call return `false` even for a national holiday.
+Check if a date is a Brazilian holiday. Accepts `{ targetDate, stateCode? }` (`IsHolidayParams`).
+
+- The check uses `targetDate`'s local calendar date, not its UTC instant.
+- `stateCode` also considers that state's holidays. An unknown code is ignored, as in `getHolidays`.
+- Returns `false` when `targetDate` is missing or not a valid `Date`, or when `stateCode` is present and not a string.
```javascript
import { isHoliday } from '@brazilian-utils/brazilian-utils';
@@ -1364,7 +1651,10 @@ isHoliday(); // false
### isBusinessDay
-Check if a date is a Brazilian business day (dia útil). Returns `false` for Saturdays, Sundays, and Brazilian holidays returned by `getHolidays` for `value`'s local calendar day (year/month/day as read locally), the same convention used by `isHoliday`. `options.includeOptional` (part of `BusinessDayOptions`, the option type every business day utility shares) defaults to `true`, so optional-type holidays (`Holiday.type === "optional"`, i.e. Carnaval and Corpus Christi) also count as non-business days; pass `false` to only treat statutory holidays this way. `options.stateCode` also considers that state's holidays; a string that is not a known state code is ignored, falling back to national holidays only, while a `stateCode` that is present and is not a string at all (a number, `null`, an object) is rejected and makes the call return `false` even for an ordinary weekday, the same split `isHoliday` makes and the value `addBusinessDays`, `subBusinessDays` and `differenceInBusinessDays` reject with `null`. A `value` that is not a valid `Date` returns `false`. Only years from 1900 through 2099 are supported, the range `getHolidays` computes; a date outside it returns `false`.
+Check if a date is a Brazilian business day (dia útil): not a Saturday, a Sunday or a holiday `getHolidays` lists for its local calendar day.
+
+- **Options** (`BusinessDayOptions`, shared by every business day util): `includeOptional` (default `true`) also counts the `"optional"` holidays, Carnaval and Corpus Christi, as non-business days; `stateCode` also counts that state's holidays.
+- Returns `false` when `value` is not a valid `Date` or its year is outside 1900 to 2099, or when `stateCode` is present and not a string.
```javascript
import { isBusinessDay } from '@brazilian-utils/brazilian-utils';
@@ -1381,7 +1671,12 @@ isBusinessDay(new Date('not a date')); // false
### addBusinessDays
-Add a number of Brazilian business days (dias úteis) to a date, skipping Saturdays, Sundays and Brazilian holidays exactly as `isBusinessDay` defines them (same `BusinessDayOptions`: `options.includeOptional`, default `true`, and `options.stateCode` work exactly as they do there). The signature is date-fns': `addBusinessDays(date, amount, options?)`. Returns a new `Date`; the input `date` is never mutated, and its time-of-day is preserved in the result. An `amount` of `0` returns a new `Date` equal to `date`, unchanged, even when `date` itself falls on a weekend or holiday, this mirrors the verified behavior of [date-fns' `addBusinessDays(date, 0)`](https://date-fns.org/docs/addBusinessDays), which also does not roll the input to the next business day. A negative `amount` walks backwards, one business day at a time, also like date-fns. Returns `null` on bad input: a `date` that is not a valid `Date`, an `amount` that is not a finite integer, or a `stateCode` that is not a string; an `options` that is not an object at all is ignored, exactly as `isBusinessDay` ignores it. Only years from 1900 through 2099 are supported, the range `getHolidays` computes; a date outside it, or a walk that leaves it, returns `null`.
+Add a number of Brazilian business days (dias úteis) to a date, skipping Saturdays, Sundays and the holidays `isBusinessDay` skips. Signature: `addBusinessDays(date, amount, options?)`, the same as date-fns.
+
+- **Options** (`BusinessDayOptions`, shared with `isBusinessDay`): `includeOptional` (default `true`) also skips Carnaval and Corpus Christi; `stateCode` also skips that state's holidays.
+- Returns a new `Date`, time of day preserved; `date` is never mutated.
+- An `amount` of `0` returns the same date, even on a weekend or holiday. A negative `amount` walks backwards.
+- Returns `null` when `date` is invalid, `amount` is not a finite integer, `stateCode` is not a string, or the result leaves the years 1900 to 2099.
```javascript
import { addBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1397,7 +1692,9 @@ addBusinessDays(new Date(2024, 0, 2), 1.5); // null (not an integer)
### subBusinessDays
-Subtract a number of Brazilian business days (dias úteis) from a date: `subBusinessDays(date, amount, options?)` is `addBusinessDays(date, -amount, options)`, which is exactly how it is implemented, so every detail above (the preserved time-of-day, the untouched input, an `amount` of `0` returning the date unchanged, the 1900-2099 range and the `null` cases) holds here too, `options.stateCode` and `options.includeOptional` included. A negative `amount` walks forwards.
+Subtract a number of Brazilian business days (dias úteis) from a date. `subBusinessDays(date, amount, options?)` is `addBusinessDays(date, -amount, options)`.
+
+- Same rules as `addBusinessDays`, `BusinessDayOptions` included. A negative `amount` walks forwards.
```javascript
import { subBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1414,7 +1711,12 @@ subBusinessDays(new Date(2024, 0, 2), 1.5); // null (not an integer)
### differenceInBusinessDays
-Count the number of Brazilian business days (dias úteis) between two dates, mirroring the semantics of [date-fns' `differenceInBusinessDays`](https://date-fns.org/docs/differenceInBusinessDays) (verified against its source), argument order included: `differenceInBusinessDays(laterDate, earlierDate, options?)`. The walk starts at `earlierDate` and stops just before `laterDate`, so `earlierDate` is counted when it is itself a business day, `laterDate` is never counted, and every business day strictly in between is counted once. Only the calendar day of each `Date` matters, the time of day is ignored. Business days are determined exactly like `isBusinessDay` (same `BusinessDayOptions`), `options.includeOptional` (default `true`) and `options.stateCode` included. The result is positive when `laterDate` is after `earlierDate` and negative when it is before it; two dates on the same calendar day return `0`. Returns `null` on bad input: a date that is not a valid `Date`, or a `stateCode` that is not a string; an `options` that is not an object at all is ignored. Only years from 1900 through 2099 are supported, the range `getHolidays` computes; a date outside it returns `null`.
+Count the Brazilian business days (dias úteis) between two dates. Signature: `differenceInBusinessDays(laterDate, earlierDate, options?)`, the same as date-fns.
+
+- **Options** (`BusinessDayOptions`, shared with `isBusinessDay`): `includeOptional` (default `true`) also skips Carnaval and Corpus Christi; `stateCode` also skips that state's holidays.
+- Counts `earlierDate` when it is a business day and every business day strictly between the two dates; `laterDate` is never counted. The time of day is ignored.
+- The result is negative when `laterDate` is before `earlierDate`, and `0` on the same calendar day.
+- Returns `null` when either date is not a valid `Date` or is outside the years 1900 to 2099, or `stateCode` is not a string.
```javascript
import { differenceInBusinessDays } from '@brazilian-utils/brazilian-utils';
@@ -1431,7 +1733,9 @@ differenceInBusinessDays(new Date(), new Date('not a date')); // null
### isValidPassport
-Check if a Brazilian passport number is valid (2 letters followed by 6 digits). Accepts both `string` and `number` input; the input is case-insensitive and any non-alphanumeric characters (spaces, dots, hyphens) are ignored. A number is accepted for symmetry with `formatPassport`/`parsePassport` but is never valid: the decimal form of a number never starts with the two letters a passport number needs.
+Check if a Brazilian passport number is valid: 2 letters followed by 6 digits.
+
+- There is no check digit, so a well-formed number is not necessarily a real passport.
```javascript
import { isValidPassport } from '@brazilian-utils/brazilian-utils';
@@ -1442,9 +1746,11 @@ isValidPassport('AB-123.456'); // true (symbols are ignored)
isValidPassport('12345678'); // false
```
+Source: [Polícia Federal](https://www.gov.br/pf/pt-br/assuntos/passaporte) and its [FAQ](https://www.gov.br/pf/pt-br/assuntos/passaporte/ajuda/duvidas_/caderneta/caderneta-numero-onde-fica-e).
+
### formatPassport
-Format a Brazilian passport number (uppercase, without symbols, capped to 8 characters). A non-string input returns an empty string.
+Format a Brazilian passport number: uppercase, without symbols, capped to 8 characters. It is the same operation as `parsePassport`, of which it is an alias.
```javascript
import { formatPassport } from '@brazilian-utils/brazilian-utils';
@@ -1455,7 +1761,7 @@ formatPassport('AB-123.456'); // 'AB123456'
### parsePassport
-Remove all non-alphanumeric characters from a passport number, uppercase the result, and cap it to 8 characters. A non-string input returns an empty string.
+Remove all non-alphanumeric characters from a passport number, uppercase the result, and cap it to 8 characters.
```javascript
import { parsePassport } from '@brazilian-utils/brazilian-utils';
@@ -1466,7 +1772,7 @@ parsePassport(' AB 123 456 '); // 'AB123456'
### generatePassport
-Generate a random valid Brazilian passport number. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a random valid Brazilian passport number.
```javascript
import { generatePassport } from '@brazilian-utils/brazilian-utils';
@@ -1478,7 +1784,10 @@ generatePassport(); // 'RY393097'
### isValidCnh
-Check if CNH is valid. Spaces, dots and hyphens around/between the digits are ignored, but any other character, a letter in particular, makes the value invalid. A value whose 11 digits are all the same is rejected before the check digits are computed, so `'11111111111'` is invalid.
+Check if a CNH is valid. Spaces, dots and hyphens are ignored; any other character makes the value invalid.
+
+- A value whose 11 digits are all the same is rejected, so `'11111111111'` is invalid.
+- The first check digit keeps a remainder of 1 as `1`, as real registry numbers do. Resolução CONTRAN nº 886/2021 says `0`.
```javascript
import { isValidCnh } from '@brazilian-utils/brazilian-utils';
@@ -1488,9 +1797,13 @@ isValidCnh('000000001-19'); // true (hyphen before the check digits)
isValidCnh('ab00000000119'); // false (letters are rejected)
```
+Source: [Resolução CONTRAN nº 886/2021, art. 4º](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/Resolucao8862021F.pdf); weights per [siga0984](https://siga0984.wordpress.com/2019/05/01/algoritmos-validacao-de-cnh/).
+
### formatCnh
-Format CNH. `options.pad` (part of `FormatCnhOptions`) left-pads the value with zeros to the full 11 digits before masking (default `false`).
+Format a CNH.
+
+- **Options** (`FormatCnhOptions`): `pad` left-pads the value with zeros to the full 11 digits before masking (default `false`).
```javascript
import { formatCnh } from '@brazilian-utils/brazilian-utils';
@@ -1501,7 +1814,7 @@ formatCnh('2650306461', { pad: true }); // 026503064-61
### parseCnh
-Remove CNH formatting, keep only digits, and cap the result to 11 digits. Returns `''` when there is no digit at all.
+Remove CNH formatting, keep only digits, and cap the result to 11 digits.
```javascript
import { parseCnh } from '@brazilian-utils/brazilian-utils';
@@ -1511,7 +1824,7 @@ parseCnh('026503064-61'); // '02650306461'
### generateCnh
-Generate a valid random CNH. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random CNH.
```javascript
import { generateCnh } from '@brazilian-utils/brazilian-utils';
@@ -1523,7 +1836,9 @@ generateCnh(); // '02650306461'
### isValidLegalNature
-Check if a legal nature code exists in the official list. The table follows IBGE/CONCLA's "Natureza Jurídica 2021": the 92 codes in force plus the 8 a past revision of the table retired, kept because they still appear in records filed while they were in force. Use `getLegalNature` to tell the two apart: a retired code comes back with `legacy: true` and the `currentCode` it corresponds to today. Only the usual mask characters (hyphens, dots, whitespace) are tolerated around the 4 digits, so `'2062a'` is rejected instead of being read as `'2062'`.
+Check if a legal nature code exists in the official list, the IBGE/CONCLA "Natureza Jurídica 2021" table. Only hyphens, dots and whitespace are tolerated around the 4 digits.
+
+- The 92 codes in force are accepted, plus the 8 a past revision retired. `getLegalNature` tells them apart (`legacy: true`).
```javascript
import { isValidLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1533,9 +1848,13 @@ isValidLegalNature('2208'); // true (retired by a past revision, still accepted)
isValidLegalNature('9999'); // false
```
+Source: [CONCLA, Natureza Jurídica 2021](https://concla.ibge.gov.br/estrutura/natjur-estrutura/natureza-juridica-2021) and its [detailed structure PDF](https://concla.ibge.gov.br/images/concla/documentacao/CONCLA-TNJ2021-EstruturaDetalhada.pdf).
+
### formatLegalNature
-Format a legal nature code. `options.pad` (part of `FormatLegalNatureOptions`) works exactly like it does in `formatCpf`/`formatCep`: with the default `false` the mask is applied progressively, as far as the value goes; with `true` the value is first left padded with zeros to the 4 digits of a complete code. Use `isValidLegalNature` to check a code.
+Format a legal nature code. Use `isValidLegalNature` to check a code.
+
+- **Options** (`FormatLegalNatureOptions`): `pad` first left-pads the value with zeros to the 4 digits of a complete code (default `false`).
```javascript
import { formatLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1558,7 +1877,7 @@ parseLegalNature('206-2'); // '2062'
### generateLegalNature
-Generate a random valid legal nature code. Only the 92 codes in force are drawn, never one of the 8 a past revision retired. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a random valid legal nature code. Only the 92 codes in force are drawn, never a retired one.
```javascript
import { generateLegalNature } from '@brazilian-utils/brazilian-utils';
@@ -1568,9 +1887,10 @@ generateLegalNature(); // '2062'
### getLegalNature
-Look a legal nature code up in the official IBGE/CONCLA table. The entry also carries the CONCLA category the code is listed under, taken from its first digit. No legal nature code starts with a zero, that first digit is the category (1 to 5), so nothing is ever padded here: a number and the string of the same digits are read identically.
+Look a legal nature code up in the official IBGE/CONCLA table. Returns `null` for an unknown code.
-A code a past revision of the table retired is still looked up, because it keeps appearing in records filed while it was in force, and comes back with `legacy: true` and the `currentCode` it corresponds to today, per the CONCLA correspondence spreadsheets. The 92 codes in force have `legacy: false` and no `currentCode`.
+- The entry (`LegalNature`) also carries the CONCLA category of the code, given by its first digit.
+- A code a past revision retired comes back with `legacy: true` and the `currentCode` it corresponds to today, or `currentCode: null` when there is no successor. Codes in force have `legacy: false` and no `currentCode`.
| Retired code | Description | Corresponds to |
| --- | --- | --- |
@@ -1607,9 +1927,13 @@ getLegalNature(206.2)?.category.description; // 'Entidades Empresariais'
getLegalNature('0000'); // null
```
+Source: [CONCLA, Natureza Jurídica 2021](https://concla.ibge.gov.br/estrutura/natjur-estrutura/natureza-juridica-2021).
+
### getLegalNatures
-Get the legal nature map keyed by code. Only the 92 codes of the CONCLA 2021 table, the ones in force, are listed by default; pass `{ includeLegacy: true }` (`GetLegalNaturesParams`) to add the 8 a past revision of the table retired.
+Get the legal nature map keyed by code. Only the 92 codes in force are listed by default.
+
+- **Options** (`GetLegalNaturesParams`): `includeLegacy` (default `false`) adds the 8 retired codes.
```javascript
import { getLegalNatures } from '@brazilian-utils/brazilian-utils';
@@ -1624,7 +1948,11 @@ getLegalNatures({ includeLegacy: true })['2208']; // 'Entidade Binacional Itaipu
### getLegalNaturesByCategory
-Get every legal nature of a CONCLA category, the group given by the first digit of the code: `1` Administração Pública, `2` Entidades Empresariais, `3` Entidades sem Fins Lucrativos, `4` Pessoas Físicas and `5` Organizações Internacionais e Outras Instituições Extraterritoriais. The category is accepted as a string or as a number, the entries come back sorted by code, and an unknown category gives `[]`. Only the codes in force are listed by default; pass `{ includeLegacy: true }` (`GetLegalNaturesByCategoryOptions`) to add the retired codes of the category, in code order.
+Get every legal nature of a CONCLA category, the group given by the first digit of the code. The category is accepted as a string or as a number.
+
+- Categories: `1` Administração Pública, `2` Entidades Empresariais, `3` Entidades sem Fins Lucrativos, `4` Pessoas Físicas and `5` Organizações Internacionais e Outras Instituições Extraterritoriais.
+- **Options** (`GetLegalNaturesByCategoryOptions`): `includeLegacy` (default `false`) adds the retired codes of the category.
+- The entries come back sorted by code. An unknown category returns `[]`.
```javascript
import { getLegalNaturesByCategory } from '@brazilian-utils/brazilian-utils';
@@ -1642,11 +1970,14 @@ getLegalNaturesByCategory('2', { includeLegacy: true }).length; // 33
getLegalNaturesByCategory('9'); // []
```
-## Voter ID
+## Voter ID (título de eleitor)
### isValidVoterId
-Check if a voter ID number is valid. Accepts both the standard 12-digit id and the 13-digit id issued by São Paulo (UF `01`) and Minas Gerais (UF `02`). Whitespace and dots are accepted around and between the `0000 0000 00 00` groups, but any other character, a letter in particular, makes the value invalid.
+Check if a voter ID number is valid. Accepts the standard 12-digit id and the 13-digit id issued by São Paulo (UF `01`) and Minas Gerais (UF `02`).
+
+- A voter ID is an 8-digit sequential number, a 2-digit federative union code (`01` to `28`) and 2 check digits.
+- Whitespace and dots are accepted around and between the groups. Any other character, a hyphen included, makes the value invalid.
```javascript
import { generateVoterId, isValidVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1654,11 +1985,19 @@ import { generateVoterId, isValidVoterId } from '@brazilian-utils/brazilian-util
const voterId = generateVoterId('SP');
isValidVoterId(voterId); // true
+isValidVoterId('102385010671'); // true (12 digits)
+isValidVoterId('1234567880191'); // true (13 digits, São Paulo)
+isValidVoterId('123456780124'); // false (invalid check digits)
```
+Source: [Resolução TSE nº 23.659/2021, art. 36](https://www.tse.jus.br/legislacao/compilada/res/2021/resolucao-no-23-659-de-26-de-outubro-de-2021), [brutils](https://github.com/brazilian-utils/python/blob/main/brutils/voter_id.py) and [siga0984](https://siga0984.wordpress.com/2019/05/01/algoritmos-validacao-de-titulo-de-eleitor/).
+
### formatVoterId
-Format a voter ID number. Uses the 12-digit grouping `0000 0000 00 00` by default; the 13-digit grouping `0000 0000 0 00 00` is used only when the sanitized value has more than 12 digits **and** its federative union code (the 10th and 11th digits) is `01` (São Paulo) or `02` (Minas Gerais), the two states whose voter ids may carry a 9-digit sequential number.
+Format a voter ID number with the 12-digit grouping `0000 0000 00 00`.
+
+- The 13-digit grouping `0000 0000 0 00 00` is used only when the value has more than 12 digits and its UF code (the 10th and 11th digits) is `01` or `02`.
+- Digits past the last slot of the pattern are dropped.
```javascript
import { formatVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1680,7 +2019,10 @@ parseVoterId('1234 5678 8 01 91'); // '1234567880191' (13-digit SP/MG voter id)
### generateVoterId
-Generate a valid random voter ID number. You can optionally provide a state code; an unknown state code falls back to `"ZZ"` (issued abroad) instead of throwing. Uses `Math.random()` internally, so it is not cryptographically secure.
+Generate a valid random voter ID number. The optional `state` argument (`StateCode`, or `"ZZ"` for a voter ID issued abroad) sets the federative union code.
+
+- An unknown state, or a value that is not a string, falls back to `"ZZ"` (UF `28`).
+- The result always has 12 digits, never the 13-digit São Paulo or Minas Gerais form.
```javascript
import { generateVoterId } from '@brazilian-utils/brazilian-utils';
@@ -1694,23 +2036,30 @@ generateVoterId('XX'); // falls back to "ZZ" instead of throwing
### isValidCns
-Check if a CNS (Cartão Nacional de Saúde) number is valid, the unique SUS (Sistema Único de Saúde) user identifier. Definitive cards (starting with 1 or 2) are validated over an embedded 11 digit PIS/PASEP/NIS derived base weighted 15 down to 5; when the raw digit computes to 10, DATASUS raises the weighted sum by 2, recomputes the digit and marks the card with the suffix `001` instead of `000`. Provisional cards (starting with 7, 8 or 9) are validated instead by a single weighted sum (weights 15 down to 1) that must be a multiple of 11. The value has to be written as the 15 digits, optionally split into the printed groups of 3-4-4-4 by whitespace, `.`, `-` or `/`, the interchangeable mask characters `isValidCpf` and `isValidCnpj` accept, a run of them between two groups included; letters among the digits, or a separator inside a group, are rejected instead of being read past.
+Check if a CNS (Cartão Nacional de Saúde) number is valid, the SUS (Sistema Único de Saúde) identifier of a user, health professional or health facility. The value must be the 15 digits, optionally split into the printed groups of 3-4-4-4 by whitespace, `.`, `-` or `/`.
-The two routines come from the [ANVISA CNS validation page](https://rni-docs.anvisa.gov.br/docs/regras_gerais/validacoes/validacaoCNS/), which sits behind a bot filter and answers HTTP 403 to non-browser clients. The [e-SUS APS page](https://integracao.esusab.ufsc.br/ledi/documentacao/regras/algoritmo_CNS.html) documents the same algorithm and is reachable without a browser, but applies the provisional routine to numbers starting with 5, 7, 8 or 9; this implementation follows ANVISA and rejects a 5-prefixed number even when its weighted sum checks out.
+- Definitive cards start with 1 or 2, provisional ones with 7, 8 or 9; each has its own modulus 11 rule.
+- A number starting with 5 is rejected, following ANVISA.
```javascript
import { isValidCns } from '@brazilian-utils/brazilian-utils';
isValidCns('123456789010000'); // true (definitive)
+isValidCns('100000000060018'); // true (definitive, raw check digit 10, suffix 001)
isValidCns('700000000000005'); // true (provisional)
isValidCns('123.4567-8901/0000'); // true (any of the mask characters)
+isValidCns('123456789010001'); // false (wrong check digit)
isValidCns('12345678901'); // false (wrong length)
isValidCns('abc123456789010000'); // false (not written as a CNS)
```
+Source: [ANVISA CNS validation page](https://rni-docs.anvisa.gov.br/docs/regras_gerais/validacoes/validacaoCNS/) and the [e-SUS APS page](https://integracao.esusab.ufsc.br/ledi/documentacao/regras/algoritmo_CNS.html).
+
### formatCns
-Format a CNS (Cartão Nacional de Saúde) number into the common display groups of 3-4-4-4 digits separated by spaces. `options.pad` (part of `FormatCnsOptions`) left-pads the value with zeros up to the 15 slots of the pattern before masking (default `false`).
+Format a CNS (Cartão Nacional de Saúde) number into the common display groups of 3-4-4-4 digits separated by spaces.
+
+- **Options** (`FormatCnsOptions`): `pad` left-pads the value with zeros up to the 15 slots of the pattern before masking (default `false`).
```javascript
import { formatCns } from '@brazilian-utils/brazilian-utils';
@@ -1722,7 +2071,7 @@ formatCns('89010001', { pad: true }); // '000 0000 8901 0001'
### parseCns
-Remove CNS (Cartão Nacional de Saúde) formatting, keep only digits, and cap the result to 15 digits. A partial value passes through as far as it goes, so it can also strip the mask off an input still being typed; use `isValidCns` to check the number itself.
+Remove CNS (Cartão Nacional de Saúde) formatting, keep only digits, and cap the result to 15 digits.
```javascript
import { parseCns } from '@brazilian-utils/brazilian-utils';
@@ -1730,13 +2079,29 @@ import { parseCns } from '@brazilian-utils/brazilian-utils';
parseCns('123 4567 8901 0000'); // '123456789010000'
```
-## Certidão
+## Certidão (civil registry certificate)
### isValidCertidao
-Check if the matrícula of a certidão de registro civil (nascimento, casamento, óbito and the other acts kept by a serventia de registro civil das pessoas naturais) is valid. The matrícula has 32 digits laid out as 6 (CNS da serventia) + 2 (acervo) + 2 (serviço) + 4 (ano) + 1 (tipo do livro) + 5 (livro) + 3 (folha) + 7 (termo) + 2 (dígitos verificadores), and both check digits are modulus 11 with the weights cycling from 2 to 10 and back through 0: the first pass starts at 2 over the 30 base digits, the second at 1 over the 31 digits that include the first check digit, and in both a remainder of 10 is read as 1. Accepts the usual mask characters and whitespace between/around groups. The layout is the one [art. 473 of the Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243) (Provimento CNJ nº 149/2023) currently publishes, with inciso II and §§ 1º and 3º to 5º in the redação of the Provimento CN nº 237/2026 and the rest of the article, § 2º included, in that of the Provimento CN nº 182/2024; the matrícula itself was instituted by the now revoked [Provimento CNJ nº 2/2009](https://atos.cnj.jus.br/atos/detalhar/1311) and got its digit structure from the also revoked [Provimento CNJ nº 3/2009, art. 7º](https://atos.cnj.jus.br/atos/detalhar/1310). The check digits are detailed by [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and implemented by [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts) and [validator-docs](https://github.com/geekcom/validator-docs/blob/master/src/validator-docs/Rules/Certidao.php).
+Check if the matrícula of a certidão de registro civil (birth, marriage, death and the other acts of a registro civil das pessoas naturais) is valid. Only a string is accepted: the 32 digits of a matrícula are more than a JavaScript number can hold.
+
+The matrícula has 32 digits, printed as `000000 00 00 0000 0 00000 000 0000000 00`:
+
+| Digits | Field |
+| --- | --- |
+| 6 | CNS da serventia |
+| 2 | acervo |
+| 2 | serviço, always `55` |
+| 4 | ano |
+| 1 | tipo do livro |
+| 5 | livro |
+| 3 | folha |
+| 7 | termo |
+| 2 | dígitos verificadores |
-The serviço digits are fixed at `55`, the code [art. 473, III](https://atos.cnj.jus.br/atos/detalhar/5243) assigns to the registro civil das pessoas naturais, so a matrícula carrying any other pair in the ninth and tenth positions is rejected however good its check digits are. The book-type digit always has to name one of the nine book types (the same `CertidaoType` returned by `getCertidaoInfo`), so a matrícula whose digit is `0` is rejected however good its check digits are, the same way `getCertidaoInfo` returns `null` for it. `options.accept` (part of `IsValidCertidaoOptions`) narrows that to the listed types; it defaults to every type, and a value that is not an array falls back to that default. Only a string is accepted: the 32 digits of a matrícula are more than a JavaScript number can hold.
+- **Options** (`IsValidCertidaoOptions`): `accept` narrows the valid book types (`CertidaoType`) to the listed ones (default: every type).
+- The serviço must be `55`, and the book-type digit must be one of the nine books (`0` is rejected).
+- Accepts the value masked or not, with whitespace between and around the groups.
```javascript
import { isValidCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1750,9 +2115,14 @@ isValidCertidao('104539 01 55 2013 1 00012 021 0000123 21', { accept: ['birth']
isValidCertidao('104539 01 55 2013 1 00012 021 0000123 21', { accept: ['death'] }); // false
```
+Source: [art. 473 of the Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243); check digits per [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts).
+
### formatCertidao
-Format the matrícula of a certidão de registro civil into the printed mask of the Provimento, the 32 digits grouped as 6 2 2 4 1 5 3 7 2 and separated by spaces. `options.pad` (part of `FormatCertidaoOptions`) left pads the value with zeros up to 32 digits (default `false`). The mask is the one of [art. 473 of the Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243). A number is accepted and read as the string of its digits, like in `formatCpf`, but a full 32 digit matrícula has to be a string: that many digits are more than a JavaScript number can hold exactly. At runtime the value is read for its digits and masked as far as they go, like in every formatter of this package, so a partial matrícula still being typed is masked progressively.
+Format the matrícula of a certidão de registro civil into the printed mask of art. 473. The 32 digits are grouped as 6 2 2 4 1 5 3 7 2 and separated by spaces.
+
+- **Options** (`FormatCertidaoOptions`): `pad` left-pads the value with zeros up to 32 digits (default `false`).
+- A number is accepted, but a full 32-digit matrícula has to be a string.
```javascript
import { formatCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1763,9 +2133,11 @@ formatCertidao('1552010100020112000012087', { pad: true }); // 000000 01 55 2010
formatCertidao(104539015520); // 104539 01 55 20 (a number is read as the string of its digits)
```
+Source: [art. 473 of the Código Nacional de Normas](https://atos.cnj.jus.br/atos/detalhar/5243).
+
### parseCertidao
-Remove the formatting of the matrícula of a certidão de registro civil, keep only digits, and cap the result to 32 digits. This only takes the mask off: use `isValidCertidao` to check the matrícula and `getCertidaoInfo` to read its fields.
+Remove the formatting of the matrícula of a certidão de registro civil, keep only digits, and cap the result to 32 digits.
```javascript
import { parseCertidao } from '@brazilian-utils/brazilian-utils';
@@ -1776,7 +2148,25 @@ parseCertidao('104539 01 55 2013 1 00012 021 0000123 21');
### getCertidaoInfo
-Parse the matrícula of a certidão de registro civil into its fields, returning `null` when the matrícula is not valid, which includes a book code that is not one of the nine books. A serviço other than the `55` that art. 473, III fixes for the registro civil das pessoas naturais also gives `null`. [Art. 473, V of the Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243) lists the codes 1 to 7; no CNJ primary text reachable today publishes the other two, the Anexo IV of the revoked Provimento CNJ nº 63/2017 included, which lists the same seven. The codes 8 (emancipação) and 9 (interdição) come from the references the check digit rule rests on: [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts) both print the nine book list. They are kept because matrículas carrying them circulate. Only a string is accepted: the 32 digits of a matrícula are more than a JavaScript number can hold.
+Parse the matrícula of a certidão de registro civil into its fields. Accepts the same input forms as `isValidCertidao` and returns `null` when the matrícula is not valid.
+
+- Returns `null` also for a serviço other than `55` and for a book code outside 1 to 9.
+- Art. 473, V lists only the book codes 1 to 7. The codes 8 (emancipação) and 9 (interdição) are also accepted.
+
+The `CertidaoInfo` result carries:
+
+| Key | Description |
+| --- | --- |
+| `registryCns` | The 6 digit CNS (Código Nacional de Serventia) of the serventia that issued the act. |
+| `acervo` | Acervo the book belongs to: `"01"` the serventia's own, `"02"` and up one per acervo it absorbed. Art. 473, §§ 3º to 5º splits the absorbed ones by the date the origin serventia was extinguished or deactivated. Up to 31/12/2009: the CNS of the incorporating unit and an acervo code from `"02"` up, one per incorporation. From 01/01/2010 on: the CNS of the incorporated unit itself and the code `"01"`, counted as that unit's own acervo. An acervo split between two or more successor serventias gets each successor's own CNS with the code `"02"`. |
+| `service` | Service rendered by the serventia, always `"55"`, the registro civil das pessoas naturais. |
+| `year` | Four digit year the act was recorded. |
+| `type` | The book the act belongs to: `"birth"`, `"marriage"`, `"religious-marriage"`, `"death"`, `"stillbirth"`, `"banns"`, `"other"`, `"emancipation"` or `"interdiction"`. |
+| `typeCode` | Raw book code, 1 to 9, as printed in the fifteenth position of the matrícula. |
+| `book` | The 5 digit book (livro) number, zero padded. |
+| `page` | The 3 digit page (folha) number, zero padded. |
+| `term` | The 7 digit term (termo) number, zero padded. |
+| `checkDigits` | The 2 modulus 11 check digits of the matrícula. |
```javascript
import { getCertidaoInfo } from '@brazilian-utils/brazilian-utils';
@@ -1798,26 +2188,15 @@ getCertidaoInfo('104539 01 55 2013 1 00012 021 0000123 21');
getCertidaoInfo('invalid'); // null
```
-The `CertidaoInfo` result carries:
-
-| Key | Description |
-| --- | --- |
-| `registryCns` | The 6 digit CNS (Código Nacional de Serventia) of the serventia that issued the act. |
-| `acervo` | Acervo the book belongs to: `"01"` the serventia's own, `"02"` and up one per acervo it absorbed. [Art. 473, §§ 3º to 5º](https://atos.cnj.jus.br/atos/detalhar/5243) splits the absorbed ones by the date the origin serventia was extinguished or deactivated: up to 31/12/2009 the matrícula carries the CNS of the incorporating unit and an acervo code from `"02"` up, one per incorporation; from 01/01/2010 on it carries the CNS of the incorporated unit itself and the code `"01"`, counted as that unit's own acervo; and an acervo split between two or more successor serventias gets each successor's own CNS with the code `"02"`. |
-| `service` | Service rendered by the serventia, always `"55"`, the registro civil das pessoas naturais. |
-| `year` | Four digit year the act was recorded. |
-| `type` | The book the act belongs to: `"birth"`, `"marriage"`, `"religious-marriage"`, `"death"`, `"stillbirth"`, `"banns"`, `"other"`, `"emancipation"` or `"interdiction"`. |
-| `typeCode` | Raw book code, 1 to 9, as printed in the fifteenth position of the matrícula. |
-| `book` | The 5 digit book (livro) number, zero padded. |
-| `page` | The 3 digit page (folha) number, zero padded. |
-| `term` | The 7 digit term (termo) number, zero padded. |
-| `checkDigits` | The 2 modulus 11 check digits of the matrícula. |
+Source: [art. 473 of the Código Nacional de Normas da Corregedoria Nacional de Justiça](https://atos.cnj.jus.br/atos/detalhar/5243); book codes 8 and 9 per [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and [validation-br](https://github.com/klawdyo/validation-br/blob/feat-certidao/src/certidao.ts).
## CEI, CNO and CAEPF
### isValidCei
-Check if a CEI (Cadastro Específico do INSS) number is valid. The CEI identifies an employer with no CNPJ, such as a construction work or a rural producer: 12 digits printed as `00.000.00000/00`, the last one a check digit calculated over the 11 base digits with the weights 7, 4, 1, 8, 5, 2, 1, 6, 3, 7 and 4. Accepts the usual mask characters and whitespace between/around groups, a run of them between two groups included. The Receita Federal does not publish this check digit rule, so it follows the reference implementations of [yii2-br-validator](https://github.com/yiibr/yii2-br-validator/blob/master/src/CeiValidator.php) and [Bigai.Documentos.Brasil](https://github.com/marcos-cruz/Documento/blob/master/src/Bigai.Documentos.Brasil/Cei/Cei.cs), cross-checked against the [Cadastro Nacional de Obras (CNO) open dataset](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno) of the Receita Federal.
+Check if a CEI (Cadastro Específico do INSS) number is valid. The CEI identifies an employer with no CNPJ, such as a construction work or a rural producer.
+
+- Layout: 12 digits printed as `00.000.00000/00`, 11 base digits and one check digit.
```javascript
import { isValidCei } from '@brazilian-utils/brazilian-utils';
@@ -1829,9 +2208,13 @@ isValidCei('24.985.96743/68'); // false (invalid check digit)
isValidCei('000000000000'); // false (repeated digits)
```
+Source: [yii2-br-validator](https://github.com/yiibr/yii2-br-validator/blob/master/src/CeiValidator.php), [Bigai.Documentos.Brasil](https://github.com/marcos-cruz/Documento/blob/master/src/Bigai.Documentos.Brasil/Cei/Cei.cs) and the [CNO open dataset](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno).
+
### formatCei
-Format a CEI (Cadastro Específico do INSS) number according to the usual `00.000.00000/00` mask, the one the reference implementations of the check digit agree on (the Receita Federal does not print it). Formats progressively, as far as the digits given go, so it can also be used as an input mask. `options.pad` (part of `FormatCeiOptions`) left pads the value with zeros up to 12 digits (default `false`).
+Format a CEI (Cadastro Específico do INSS) number with the usual `00.000.00000/00` mask.
+
+- **Options** (`FormatCeiOptions`): `pad` left-pads the value with zeros up to 12 digits (default `false`).
```javascript
import { formatCei } from '@brazilian-utils/brazilian-utils';
@@ -1843,7 +2226,7 @@ formatCei('249', { pad: true }); // 00.000.00002/49
### parseCei
-Remove CEI (Cadastro Específico do INSS) formatting, keep only digits, and cap the result to 12 digits. A partial value passes through as far as it goes; use `isValidCei` to check the number itself.
+Remove CEI (Cadastro Específico do INSS) formatting, keep only digits, and cap the result to 12 digits.
```javascript
import { parseCei } from '@brazilian-utils/brazilian-utils';
@@ -1853,7 +2236,9 @@ parseCei('27.729.71181/87'); // '277297118187'
### isValidCno
-Check if a CNO (Cadastro Nacional de Obras) number is valid. The CNO replaced the CEI for construction works and kept its numbering, so a work registered under a legacy CEI keeps the same number and both registries validate identically: 12 digits printed as `00.000.00000/00` with a check digit calculated over the 11 base digits. The Receita Federal does not publish the check digit rule; it was confirmed against the [Cadastro Nacional de Obras (CNO) open dataset](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno) of the Receita Federal: every work in the Minas Gerais extract of that dataset passes this check. The catalogue page itself publishes only the dataset's description and download links, not that result.
+Check if a CNO (Cadastro Nacional de Obras) number is valid. The CNO replaced the CEI for construction works and kept its numbering.
+
+- Same rules as `isValidCei`.
```javascript
import { isValidCno } from '@brazilian-utils/brazilian-utils';
@@ -1865,9 +2250,13 @@ isValidCno('110840168063'); // false (invalid check digit)
isValidCno('000000000000'); // false (repeated digits)
```
+Source: [CNO page of the Receita Federal](https://www.gov.br/receitafederal/pt-br/assuntos/orientacao-tributaria/cadastros/cno) and the [CNO open dataset](https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-de-obras-cno).
+
### formatCno
-Format a CNO (Cadastro Nacional de Obras) number. The CNO kept the CEI's numbering, so both share the same 12 digit, `00.000.00000/00` mask, the one the reference implementations of the check digit agree on (the Receita Federal does not print it). Formats progressively, as far as the digits given go, so it can also be used as an input mask. `options.pad` (part of `FormatCnoOptions`) left pads the value with zeros up to 12 digits (default `false`).
+Format a CNO (Cadastro Nacional de Obras) number.
+
+- Same rules as `formatCei`: the `00.000.00000/00` mask, with `pad` in `FormatCnoOptions`.
```javascript
import { formatCno } from '@brazilian-utils/brazilian-utils';
@@ -1879,7 +2268,7 @@ formatCno('979', { pad: true }); // 00.000.00009/79
### parseCno
-Remove CNO (Cadastro Nacional de Obras) formatting, keep only digits, and cap the result to 12 digits, the numbering the CNO kept from the CEI. A shorter value passes through as far as it goes; use `isValidCno` to check the number itself.
+Remove CNO (Cadastro Nacional de Obras) formatting, keep only digits, and cap the result to 12 digits, the numbering the CNO kept from the CEI.
```javascript
import { parseCno } from '@brazilian-utils/brazilian-utils';
@@ -1889,7 +2278,10 @@ parseCno('11.113.01373/68'); // '111130137368'
### isValidCaepf
-Check if a CAEPF (Cadastro de Atividade Econômica da Pessoa Física) number is valid. The CAEPF replaced the CEI for individuals who hire employees: 14 digits printed as `000.000.000/000-00`, formed by the 9 digit CPF base of the holder, a 3 digit sequence for the holder's several registrations and 2 check digits. Both check digits are the CNPJ's modulus 11 in the formulation of the cited reference: the weights cycle from 9 down to 2 from the right and the check digit is the remainder itself, with a remainder of 10 read as 0 — the same digit the CNPJ's 2-to-9 weights with `11 - remainder` produce. The resulting pair is then shifted by 12, wrapping around 100. A base whose 12 digits are all the same is rejected before the check digits are computed, the way `isValidCei` and `isValidCno` reject a repeated CEI/CNO number, so the otherwise well-formed `00000000000012` is invalid. The Receita Federal does not publish the layout or the check digit rule: both are described by [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and implemented the same way by [brazilian-values](https://github.com/VitorLuizC/brazilian-values/blob/master/src/validators/isCAEPF.ts).
+Check if a CAEPF (Cadastro de Atividade Econômica da Pessoa Física) number is valid. The CAEPF replaced the CEI for individuals who hire employees, such as rural producers.
+
+- Layout: 14 digits printed as `000.000.000/000-00`: the 9-digit CPF base of the holder, a 3-digit sequence and 2 check digits.
+- Both check digits follow the CNPJ's modulus 11; the pair is then shifted by 12, wrapping around 100.
```javascript
import { isValidCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1902,9 +2294,13 @@ isValidCaepf('00000000000000'); // false (repeated base digits)
isValidCaepf('00000000000012'); // false (repeated base digits)
```
+Source: [ghiorzi.org](http://ghiorzi.org/DVnew.htm) and [brazilian-values](https://github.com/VitorLuizC/brazilian-values/blob/master/src/validators/isCAEPF.ts).
+
### formatCaepf
-Format a CAEPF (Cadastro de Atividade Econômica da Pessoa Física) number according to the usual `000.000.000/000-00` mask, the one the sources of the check digit rule agree on (the Receita Federal does not print it). Formats progressively, as far as the digits given go, so it can also be used as an input mask. `options.pad` (part of `FormatCaepfOptions`) left pads the value with zeros up to 14 digits (default `false`).
+Format a CAEPF (Cadastro de Atividade Econômica da Pessoa Física) number with the usual `000.000.000/000-00` mask.
+
+- Same rules as `formatCei`, with `pad` (`FormatCaepfOptions`) padding up to 14 digits (default `false`).
```javascript
import { formatCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1916,7 +2312,7 @@ formatCaepf('184', { pad: true }); // 000.000.000/001-84
### parseCaepf
-Remove CAEPF (Cadastro de Atividade Econômica da Pessoa Física) formatting, keep only digits, and cap the result to 14 digits. A shorter value passes through as far as it goes; use `isValidCaepf` to check the number itself.
+Remove CAEPF (Cadastro de Atividade Econômica da Pessoa Física) formatting, keep only digits, and cap the result to 14 digits.
```javascript
import { parseCaepf } from '@brazilian-utils/brazilian-utils';
@@ -1928,7 +2324,11 @@ parseCaepf('293.118.610/001-84'); // '29311861000184'
### isValidCbo
-Check if a CBO (Classificação Brasileira de Ocupações) code exists in the MTE occupation table. Accepts the code with or without the hyphen mask, or as a number. A string is only read as a code when it is written in one of those forms (the 6 digits, or the `NNNN-NN` mask, with a single separator between the groups and optional surrounding whitespace), and a number only when it is a non-negative safe integer. A CBO code is always 6 digits and its leading zeros are part of it, so a value written as bare digits is left padded with zeros to 6 whether it comes as a string or as a number, exactly like `getBankByCode` pads a bank code: `10205`, `'10205'` and `'010205'` are the same code. A masked value already carries its separators and is read as written.
+Check if a CBO (Classificação Brasileira de Ocupações) code exists in the official CBO 2002 table.
+
+- Accepts a string with the 6 digits or with the `NNNN-NN` mask, or a number.
+- A masked string needs a single separator (space, `.`, `-` or `/`) between the groups. Any other string is rejected instead of having its digits picked out.
+- Bare digits are left padded with zeros to 6, as a string or as a number. A masked value is read as written.
```javascript
import { isValidCbo } from '@brazilian-utils/brazilian-utils';
@@ -1943,11 +2343,13 @@ isValidCbo('2124abc05'); // false (not a documented form)
isValidCbo(-212405); // false (not a non-negative safe integer)
```
-The occupation titles come from the [official CBO 2002 occupation table published by the MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
+Source: [CBO 2002 occupation table published by the MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
### parseCbo
-Remove CBO (Classificação Brasileira de Ocupações) formatting, keep only digits, and cap the result to 6 digits. A shorter value passes through as far as it goes and nothing is left padded here, so the leading zero of a code such as `010205` has to be written out; use `getCbo` or `isValidCbo`, which do pad a bare numeric code, to look an occupation up.
+Remove CBO (Classificação Brasileira de Ocupações) formatting, keep only digits, and cap the result to 6 digits.
+
+- Nothing is left padded: the leading zero of a code such as `010205` has to be written out. Use `getCbo` or `isValidCbo` to look an occupation up.
```javascript
import { parseCbo } from '@brazilian-utils/brazilian-utils';
@@ -1957,7 +2359,9 @@ parseCbo('2124-05'); // '212405'
### getCbo
-Look a CBO (Classificação Brasileira de Ocupações) code up and get its official occupation title, in the `{ code, description }` record every lookup of this library returns. A value written as bare digits keeps its implied leading zeros, as a string as much as a number: `getCbo(10205)` and `getCbo('10205')` are both read as `010205`. Same input rules as `isValidCbo`: a string has to be written as the 6 digits or with the `NNNN-NN` mask, and a number has to be a non-negative safe integer.
+Look a CBO (Classificação Brasileira de Ocupações) code up and get its official occupation title. The result is a `Cbo` record: `{ code, description }`.
+
+- Same rules as `isValidCbo`. Returns `null` when the code is unknown or the value is not in a documented form.
```javascript
import { getCbo } from '@brazilian-utils/brazilian-utils';
@@ -1969,11 +2373,13 @@ getCbo('000000'); // null
getCbo('2124abc05'); // null (not a documented form)
```
-The occupation titles come from the [official CBO 2002 occupation table published by the MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
+Source: [CBO 2002 occupation table published by the MTE](https://www.gov.br/trabalho-e-emprego/pt-br/assuntos/cbo/servicos/downloads/cbo2002-ocupacao.csv).
### isValidCnae
-Check if a CNAE (Classificação Nacional de Atividades Econômicas) subclass code exists in the [CNAE-Subclasses 2.3 table published by IBGE](https://concla.ibge.gov.br/busca-online-cnae.html), the current subclass revision of CNAE 2.0. Accepts the code with or without the `NNNN-N/NN` mask, or as a number. A string is only read as a code when it is written in one of those forms (the 7 digits, or the mask, with a single separator between the groups and optional surrounding whitespace), and a number only when it is a non-negative safe integer. A CNAE subclass code is always 7 digits and its leading zeros are part of it, so a value written as bare digits is left padded with zeros to 7 whether it comes as a string or as a number: `111301`, `'111301'` and `'0111301'` are the same code. A masked value already carries its separators and is read as written.
+Check if a CNAE (Classificação Nacional de Atividades Econômicas) subclass code exists in the CNAE-Subclasses 2.3 table, the current subclass revision of CNAE 2.0.
+
+- Same rules as `isValidCbo`, with 7 digits and the `NNNN-N/NN` mask.
```javascript
import { isValidCnae } from '@brazilian-utils/brazilian-utils';
@@ -1987,9 +2393,14 @@ isValidCnae('0111abc301'); // false (not a documented form)
isValidCnae(-111301); // false (not a non-negative safe integer)
```
+Source: [CNAE-Subclasses 2.3 at CONCLA/IBGE](https://concla.ibge.gov.br/busca-online-cnae.html) and the [IBGE subclasses API](https://servicodados.ibge.gov.br/api/v2/cnae/subclasses).
+
### formatCnae
-Format a CNAE (Classificação Nacional de Atividades Econômicas) subclass code. `options.pad` (part of `FormatCnaeOptions`) works exactly like it does in `formatCpf`/`formatCep`: with the default `false` the mask is applied progressively, as far as the value goes, which is what an input being typed into needs; with `true` the value is first left padded with zeros to the 7 digits of a complete subclass code, so it always comes back fully masked. A number is treated exactly like the string of its digits, so it is only padded under `pad: true`. Like every formatter of this package, the value is read for its digits and masked as far as they go: characters outside the mask are dropped and a number is read as the string of its digits, sign and decimal point included. Use `isValidCnae` to check a code.
+Format a CNAE (Classificação Nacional de Atividades Econômicas) subclass code. Only the structure changes; use `isValidCnae` to check a code against the table.
+
+- **Options** (`FormatCnaeOptions`): `pad` (default `false`) first left pads the value with zeros to the 7 digits of a complete code. Without it the mask is applied as far as the value goes.
+- Characters outside the mask are dropped, and a number is read as the string of its digits. Returns `''` when there is no digit at all.
```javascript
import { formatCnae } from '@brazilian-utils/brazilian-utils';
@@ -2005,7 +2416,9 @@ formatCnae(-6201501); // 6201-5/01
### parseCnae
-Remove CNAE (Classificação Nacional de Atividades Econômicas) formatting, keep only digits, and cap the result to the 7 digits of a complete subclass code. Nothing is left padded here; use `getCnae` or `isValidCnae`, which do pad a bare numeric code, to look a subclass up.
+Remove CNAE (Classificação Nacional de Atividades Econômicas) formatting, keep only digits, and cap the result to the 7 digits of a complete subclass code.
+
+- Same rules as `parseCbo`: nothing is left padded here.
```javascript
import { parseCnae } from '@brazilian-utils/brazilian-utils';
@@ -2016,7 +2429,10 @@ parseCnae('62'); // '62' (a partial code is kept as written)
### getCnae
-Look a CNAE (Classificação Nacional de Atividades Econômicas) subclass code up and get its code and official description. `code` comes back as the 7 bare digits, like every other lookup of this library; pass it to `formatCnae` for the `NNNN-N/NN` form. A value written as bare digits keeps its implied leading zeros, as a string as much as a number: `getCnae(111301)` and `getCnae('111301')` are both read as `0111301`. Same input rules as `isValidCnae`: a string has to be written as the 7 digits or with the `NNNN-N/NN` mask, and a number has to be a non-negative safe integer.
+Look a CNAE (Classificação Nacional de Atividades Econômicas) subclass code up and get its code and official description. The result is a `Cnae` record: `{ code, description }`.
+
+- Same rules as `getCbo`, with 7 digits and the `NNNN-N/NN` mask.
+- `code` comes back as the 7 bare digits; pass it to `formatCnae` for the `NNNN-N/NN` form.
```javascript
import { formatCnae, getCnae } from '@brazilian-utils/brazilian-utils';
@@ -2029,9 +2445,13 @@ getCnae('0111abc301'); // null (not a documented form)
formatCnae(getCnae('6201501')?.code); // 6201-5/01 (the mask is the formatter's job)
```
+Source: [CNAE-Subclasses 2.3 at CONCLA/IBGE](https://concla.ibge.gov.br/busca-online-cnae.html) and the [IBGE subclasses API](https://servicodados.ibge.gov.br/api/v2/cnae/subclasses).
+
### isValidNcm
-Check if an NCM (Nomenclatura Comum do Mercosul) code exists in the current table published by Siscomex/MDIC. Accepts the code with or without the dotted mask, or as a number. A string is only read as a code when it is written in one of those forms (the 8 digits, or the `NNNN.NN.NN` mask, with a single separator between the groups and optional surrounding whitespace), and a number only when it is a non-negative safe integer. An NCM code is always 8 digits and its leading zeros are part of it, so a value written as bare digits is left padded with zeros to 8 whether it comes as a string or as a number: `1012100`, `'1012100'` and `'01012100'` are the same code. A masked value already carries its separators and is read as written.
+Check if an NCM (Nomenclatura Comum do Mercosul) code exists in the current table published by Siscomex/MDIC.
+
+- Same rules as `isValidCbo`, with 8 digits and the `NNNN.NN.NN` mask.
```javascript
import { isValidNcm } from '@brazilian-utils/brazilian-utils';
@@ -2045,9 +2465,14 @@ isValidNcm('abc01012100'); // false (not a documented form)
isValidNcm(-84713012); // false (not a non-negative safe integer)
```
+Source: [NCM nomenclature published by the Portal Único Siscomex](https://portalunico.siscomex.gov.br/classif/api/publico/nomenclatura/download/json).
+
### formatNcm
-Format an NCM (Nomenclatura Comum do Mercosul) code. `options.pad` (part of `FormatNcmOptions`) works exactly like it does in `formatCpf`/`formatCep`: with the default `false` the mask is applied progressively, as far as the value goes, which is what an input being typed into needs; with `true` the value is first left padded with zeros to the 8 digits of a complete code, so it always comes back fully masked. A number is treated exactly like the string of its digits, so it is only padded under `pad: true`. Like every formatter of this package, the value is read for its digits and masked as far as they go: characters outside the mask are dropped and a number is read as the string of its digits, sign and decimal point included. Use `isValidNcm` to check a code.
+Format an NCM (Nomenclatura Comum do Mercosul) code. Only the structure changes; use `isValidNcm` to check a code against the table.
+
+- **Options** (`FormatNcmOptions`): `pad` (default `false`) first left pads the value with zeros to the 8 digits of a complete code.
+- Same rules as `formatCnae`, with the `NNNN.NN.NN` mask.
```javascript
import { formatNcm } from '@brazilian-utils/brazilian-utils';
@@ -2062,7 +2487,9 @@ formatNcm(-84713012); // 8471.30.12
### parseNcm
-Remove NCM (Nomenclatura Comum do Mercosul) formatting, keep only digits, and cap the result to the 8 digits of a complete code. Nothing is left padded here; use `isValidNcm`, which does pad a bare numeric code, to check a code against the official table.
+Remove NCM (Nomenclatura Comum do Mercosul) formatting, keep only digits, and cap the result to the 8 digits of a complete code.
+
+- Same rules as `parseCbo`: nothing is left padded here.
```javascript
import { parseNcm } from '@brazilian-utils/brazilian-utils';
@@ -2073,9 +2500,11 @@ parseNcm('8471'); // '8471' (a partial code is kept as written)
### isValidCfop
-Check if a CFOP (Código Fiscal de Operações e Prestações) code exists in the official table. The table is the [consolidated Anexo II of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), the text in force (current wording given by Ajuste SINIEF 03/24, last amended by [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25)), not the frozen 2001 text of Ajuste SINIEF 07/01. Only operable codes count: the group and subgroup headings of the official nomenclature, the codes ending in `00` and `50` (1000, 1100, 1150, 5350, ...), are section titles rather than codes a document can carry, so they are rejected.
+Check if a CFOP (Código Fiscal de Operações e Prestações) code exists in the official table, the consolidated Anexo II of Convênio SINIEF s/nº 1970 in force.
-A string is only read as a code when it is written in one of the documented forms (the 4 digits, or the `N.NNN` form the annex prints, with a single separator between the groups and optional surrounding whitespace), and a number only when it is a non-negative safe integer. No CFOP code starts with a zero, its first digit is the operation group (1 to 7), so nothing is ever padded here: a number and the string of the same digits are read identically.
+- Only operable codes count: the group and subgroup headings, the codes ending in `00` and `50`, are rejected.
+- Accepts a string with the 4 digits or with the `N.NNN` form, with a single separator (space, `.`, `-` or `/`), or a number. Any other string is rejected.
+- No CFOP code starts with a zero, so nothing is padded.
```javascript
import { isValidCfop } from '@brazilian-utils/brazilian-utils';
@@ -2089,9 +2518,13 @@ isValidCfop('abc5102'); // false (not a documented form)
isValidCfop(-5102); // false (not a non-negative safe integer)
```
+Source: [consolidated Anexo II of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), last amended by [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25).
+
### parseCfop
-Remove CFOP (Código Fiscal de Operações e Prestações) formatting, keep only digits, and cap the result to 4 digits. A shorter value passes through as far as it goes. No CFOP code starts with a zero, its first digit is the operation group from 1 to 7, so nothing is ever padded here.
+Remove CFOP (Código Fiscal de Operações e Prestações) formatting, keep only digits, and cap the result to 4 digits.
+
+- No CFOP code starts with a zero, so nothing is padded here.
```javascript
import { parseCfop } from '@brazilian-utils/brazilian-utils';
@@ -2101,7 +2534,9 @@ parseCfop('5.102'); // '5102'
### getCfop
-Look a CFOP (Código Fiscal de Operações e Prestações) code up and get its code and official description, as the [consolidated Anexo II of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24) words it, in the text in force, last amended by [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25). The group and subgroup headings of the official nomenclature, the codes ending in `00` and `50`, are not in the table and give `null`. Same input rules as `isValidCfop`.
+Look a CFOP (Código Fiscal de Operações e Prestações) code up and get its code and official description. The result is a `Cfop` record: `{ code, description }`.
+
+- Same rules as `isValidCfop`. Returns `null` for a heading, an unknown code or a value not in a documented form.
```javascript
import { getCfop } from '@brazilian-utils/brazilian-utils';
@@ -2113,6 +2548,8 @@ getCfop('5350'); // null (a subgroup heading, not an operable code)
getCfop('abc5102'); // null (not a documented form)
```
+Source: [consolidated Anexo II of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cfop_cvsn_1-6.24), last amended by [Ajuste SINIEF 39/25](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2025/AJ039_25).
+
### isValidCst
Check if a CST (Código de Situação Tributária) code is valid for a given tax. Pass the tax through `options.tax`:
@@ -2124,13 +2561,9 @@ Check if a CST (Código de Situação Tributária) code is valid for a given tax
| `pis` | 2 digits | `01`-`09`, `49`, `50`-`56`, `60`-`67`, `70`-`75`, `98`, `99` |
| `cofins` | 2 digits | same table as `pis` |
-`options.tax` (part of `IsValidCstOptions`) is optional: omit it to accept a code that exists in any one of the four tables above. A `tax` outside those four values falls back to that same default at runtime, the way every other scalar option of this library treats a value it does not know.
-
-The ICMS Tabela B is the one in force: the [consolidated Anexo I of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70), whose current wording came from [Ajuste SINIEF 39/23](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2023/ajuste-sinief-39-23) (effective 01.12.23) and which [Ajuste SINIEF 20/24](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2024/AJ020_24) amended by striking items 12, 13, 52, 72 and 74 (effects from 09.07.24) before they ever took effect: 39/23 had deferred their effect to 1º de outubro de 2024, so the revocation reached them first and those codes were never in force. `02`, `15`, `53` and `61` are its monofasia de combustíveis codes.
-
-A string is only read as a code when it is written in one of the documented forms (the 2 digits of a Tabela B code, or the 3 digits of the ICMS form with an optional single separator after the origin digit, plus optional surrounding whitespace), and a number only when it is a non-negative safe integer. The origin digit is the only boundary a printed CST has, so `'0 10'` and `'1-10'` are read while `'0-0'`, `'11-0'` and `'00-'` are not.
-
-A single digit is narrower than either documented form, so it is left padded with zeros to the 3 digits of the ICMS form, whether it comes as a string or as a number: `0`, `'0'` and `'000'` are all the ICMS code `000`. A 2 digit value is already a documented form, a Tabela B code, and is read as written, so a Tabela B code keeps its own two digits: `'07'`, not `7`, which is the ICMS code `007`.
+- **Options** (`IsValidCstOptions`): `tax` picks the table. Omitted, or outside those four values, every table is accepted.
+- Accepts a string with the 2 digits of a Tabela B code or the 3 digits of the ICMS form, or a number. The ICMS form may have a single separator (space, `.`, `-` or `/`) after the origin digit.
+- A single digit is padded to the 3-digit ICMS form; a 2-digit string is a Tabela B code, while the number `7` is the ICMS code `007`.
```javascript
import { isValidCst } from '@brazilian-utils/brazilian-utils';
@@ -2149,30 +2582,36 @@ isValidCst('abc110'); // false (not a documented form)
isValidCst(-110); // false (not a non-negative safe integer)
```
+Source: ICMS Tabela B from [Anexo I of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70) as amended by [Ajuste SINIEF 20/24](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2024/AJ020_24); IPI, PIS and COFINS from [IN RFB nº 1.009/2010](https://normas.receita.fazenda.gov.br/sijut2consulta/link.action?idAto=15974).
+
### isValidCsosn
-Check if a CSOSN (Código de Situação da Operação no Simples Nacional) code is one of the 10 codes of the [consolidated Anexo III-A of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70), the table Ajuste SINIEF 03/2010 instituted: `101`, `102`, `103`, `201`, `202`, `203`, `300`, `400`, `500` or `900`.
+Check if a CSOSN (Código de Situação da Operação no Simples Nacional) code is one of the 10 codes of the official table: `101`, `102`, `103`, `201`, `202`, `203`, `300`, `400`, `500` or `900`.
-A string is only read as a code when it is written as the bare 3 digits with optional surrounding whitespace: a CSOSN has no printed grouping (the NF-e carries the origin digit in its own `orig` field), so `'1-01'` is rejected; a number is read only when it is a non-negative safe integer. No CSOSN code starts with a zero, the table runs from `101` to `900`, so nothing is ever padded here: a number and the string of the same digits are read identically.
+- Accepts a string with the bare 3 digits, or a number. A CSOSN has no printed grouping, so `'1-01'` is rejected.
```javascript
import { isValidCsosn } from '@brazilian-utils/brazilian-utils';
isValidCsosn('101'); // true
+isValidCsosn(900); // true
isValidCsosn('999'); // false
isValidCsosn('abc101'); // false (not a documented form)
isValidCsosn(-101); // false (not a non-negative safe integer)
```
+Source: [consolidated Anexo III-A of Convênio SINIEF s/nº 1970](https://www.confaz.fazenda.gov.br/legislacao/ajustes/sinief/cvsn_70) and [Ajuste SINIEF 03/2010](https://www.confaz.fazenda.gov.br/legislacao/ajustes/2010/aj_003_10).
+
## Text
### capitalize
-Transforms the first letter into a capital one of each word, the way a Brazilian name, company name or address is written, with no options needed. Words are separated by whitespace, by `-` and `/`, by the apostrophe (`'d'oeste'` becomes `'d'Oeste'`) and by punctuation that touches a word (`'(empresa)'` becomes `'(Empresa)'`, `'bairro:centro'` becomes `'Bairro:Centro'`), so `'MOGI-GUAÇU'` becomes `'Mogi-Guaçu'`; the separators are kept where they are. Every run of whitespace (tabs, newlines, repeated spaces) collapses into a single space, and the leading and trailing whitespace is dropped. The particles of foreign-origin names (`del`, `della`, `di`, `du`, `van`, `von`, `der`, `den`) stay lower case like the Portuguese prepositions, and so does the elided `d'`, wherever it appears, whenever an apostrophe and a word follow it (`'dias d'ávila'` becomes `'Dias d'Ávila'`); a single letter written right after an apostrophe is the English possessive and stays lower case too (`"bob's"` becomes `"Bob's"`).
-
-`options.lowerCaseWords` defaults to the Portuguese prepositions, articles and conjunctions that stay in lower case inside a proper name (`de`, `da`, `do`, `e`, ...), and they are only written in lower case when they link two words: one of them that is the first word, that ends the value, or that is followed by punctuation is a designator instead and keeps its capital (`'rua a, 100'` becomes `'Rua A, 100'` and `'condomínio a, quadra d, lote o'` becomes `'Condomínio A, Quadra D, Lote O'`). `options.upperCaseWords` defaults to the company designations and document abbreviations written in upper case in Brazilian usage (`LTDA`, `S.A.`, `S/A`, `S.S.`, `S/S`, `ME`, `EPP`, `MEI`, `EIRELI`, `CIA`, `SCP`, `CNPJ`, `CPF`, `RG`, `CEP`, `UF`) plus the roman numerals that appear in names and addresses (`II` through `XXIII`, except `VI`, which collides with the pt-BR verb form "vi"). `SA` without punctuation is deliberately absent, since it is indistinguishable from the surname "Sá" typed without its accent, while `ME` is also the pronoun "me", so it is only written in upper case in the designation position, as the last word of the value (`'fulano comércio me'` becomes `'Fulano Comércio ME'`) or right before another designation (`'fulano me epp'` becomes `'Fulano ME EPP'`); anywhere else it is an ordinary word (`'diga-me a verdade'` becomes `'Diga-Me a Verdade'`, `'não-me-toque'` becomes `'Não-Me-Toque'`). `S/A` and `S/S` are matched across the slash even though a slash separates words. A two letter word that follows a `/` is upper-cased when it is the code of a Brazilian state (`'porto alegre/rs'` becomes `'Porto Alegre/RS'`); that rule is structural and stays on even when `upperCaseWords` is given, while a state code that does not follow a `/` is left alone.
+Capitalize the first letter of each word, the way a Brazilian name, company name or address is written, with no options needed.
-Either list given in `options` replaces its default entirely, and the comparison against both is case-insensitive (pt-BR locale). Options are typed as `CapitalizeOptions`. Every other word is capitalized letter by letter: `'İSTANBUL'` becomes `'İstanbul'`, and a first letter whose upper case is two letters (`ß`, the `fi` ligature) keeps its case, so `'straße'` becomes `'Straße'` and `'ßa'` stays `'ßa'`.
+- **Options** (`CapitalizeOptions`): `lowerCaseWords`, words kept in lower case between two words, by default prepositions and articles such as `de`, `da`, `do`, `e`; `upperCaseWords`, words always in upper case, by default company designations and abbreviations such as `LTDA`, `S.A.`, `ME`, `CNPJ` and roman numerals. A list replaces its default.
+- Words split at whitespace, `-`, `/`, apostrophes and adjoining punctuation; whitespace runs collapse into one space.
+- A lower-case word that is first, last or followed by punctuation is a designator and keeps its capital.
+- `ME` is upper-cased only as a designation (last word, or before another designation); `SA` without dots is left alone (the surname Sá). A state code after a `/` is upper-cased even with `upperCaseWords` given.
```javascript
import { capitalize } from '@brazilian-utils/brazilian-utils';
@@ -2202,9 +2641,13 @@ capitalize('doc inválido', { upperCaseWords: ['DOC'] }); // DOC Inválido (case
capitalize(' josé maria '); // José Maria (every run of whitespace, tabs and newlines included, collapses into one space)
```
+Source: [Manual de Redação da Presidência da República](https://www4.planalto.gov.br/centrodeestudos/assuntos/manual-de-redacao-da-presidencia-da-republica/manual-de-redacao.pdf).
+
### removeAccents
-Remove diacritical marks (accents, tildes, cedillas) from a string, decomposing every accented character into its base letter plus combining marks (Unicode NFD) and dropping the combining marks.
+Remove diacritical marks (accents, tildes, cedillas) from a string.
+
+- Every combining mark (Unicode general category M) is dropped, so accents from any script go.
```javascript
import { removeAccents } from '@brazilian-utils/brazilian-utils';
@@ -2216,30 +2659,52 @@ removeAccents('Açaí'); // 'Acai'
removeAccents(''); // ''
```
-## isValidIe
+## Inscrição estadual (IE)
+
+### isValidIe
+
+Check if an inscrição estadual (state registration) is valid for a state. **Deprecated:** the positional form `isValidIe(stateCode, ie)` still works but is deprecated; use the object form `isValidIe({ value, stateCode })`.
-Check if inscrição estadual (state registration) is valid. The state code is case-insensitive. Notable per-state rules: GO accepts prefixes `10`, `11` and `15`; PA accepts `15` and `75`-`79`; MS accepts `28` and `50`; SP has a produtor rural pattern `P0MMMSSSSD000`; TO uses 11-digit type codes (`01`, `02`, `03`, `99`). TO also accepts a 9-digit form, applying the same modulus 11 rule to the first eight digits; the SINTEGRA page documents only the 11-digit one, so that shape is 2.3.0 behaviour kept for compatibility rather than a published rule. An all-zero registration is accepted wherever the published formula yields a check digit of 0 for it (AM, BA with 8 or 9 digits, CE, ES, MG, MT, PB, PE, PI, PR, RJ, RS, SC, SE, SP and TO with 9 digits), unlike `isValidCpf` and `isValidCnpj`, which reject repeated digits. AM is on that list through the second branch of its published formula only: the page's first branch, `Se Soma < 11 Então Dígito = 11 - Soma`, gives 11 for an all-zero registration, while the `resto <= 1 ⇒ 0` branch, the one implemented here, gives 0. The registration and the state code go together in a single object, typed as `IsValidIeParams`; the 2.3.0 form, `isValidIe(stateCode, ie)`, still works and is deprecated.
+- Takes a single object (`IsValidIeParams`): `value` is the registration and `stateCode` the state it belongs to (a `StateCode`, case-insensitive).
+- GO, PA, MS, SP, TO, DF, PE, AL and RJ have special cases (extra prefixes or formats, or a deviation from the SINTEGRA page); see the JSDoc in `src/is-valid-ie` for the details.
+- An all-zero registration is accepted wherever the published formula yields a check digit of 0 for it: AM, CE, ES, MG, MT, PB, PE, PI, PR, RJ, RS, SC, SE and SP, plus BA with 8 or 9 digits and TO with 9 digits.
```javascript
import { isValidIe } from '@brazilian-utils/brazilian-utils';
+isValidIe({ value: '110042490114', stateCode: 'SP' }); // true
+isValidIe({ value: 'P011004243002', stateCode: 'SP' }); // true (produtor rural)
isValidIe({ value: '0187634580933', stateCode: 'AC' }); // false
isValidIe({ value: '109161793', stateCode: 'go' }); // true (case-insensitive)
```
-## isValidEmail
+Source: [SINTEGRA state pages](http://www.sintegra.gov.br/insc_est.html) and the [SEFAZ-GO roteiro de crítica](https://goias.gov.br/economia/roteiro-de-critica-da-inscricao-estadual-de-goias/).
-Check if email is valid. The accepted set is a practical subset of the WHATWG HTML [valid e-mail address](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) definition, not of [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322). The local part is limited to letters, digits and `_'+-.`, and may not start with a dot, end with a dot or an apostrophe, or contain two dots in a row. The domain must carry at least one dot, and each dotted label follows the WHATWG production `[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?`, so a label may neither start nor end with a hyphen nor exceed 63 characters; the final label is alphabetic and 2 to 63 letters long, so `user@example.c1` is rejected. Quoted local parts (`"john doe"@example.com`) and address literals (`john@[127.0.0.1]`) are rejected.
+## Email
+
+### isValidEmail
+
+Check if an email address is valid. A practical subset of the WHATWG HTML definition.
+
+- Local part: letters, digits and `_'+-.`, with no leading or trailing dot and no two dots in a row.
+- Domain: at least one dot, labels of up to 63 characters, final label 2 to 63 letters; quoted local parts and address literals are rejected.
```javascript
import { isValidEmail } from '@brazilian-utils/brazilian-utils';
isValidEmail('john.doe@hotmail.com'); // true
+isValidEmail('invalid.email'); // false
```
-## isValidCreditCard
+Source: [WHATWG HTML, valid e-mail address](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) and [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322).
+
+## Credit card
-Check if a payment card number is valid using the Luhn algorithm ([ISO/IEC 7812-1](https://www.iso.org/standard/70484.html)). Accepts the usual mask characters (whitespace, `.`, `-` and `/`, the interchangeable set `isValidCpf` and `isValidCnpj` accept) between any two digits and whitespace around the value; any other character makes the value invalid. They are accepted between any two digits rather than at fixed positions because the printed grouping of a PAN changes with the brand (4-4-4-4 for Visa and Mastercard, 4-6-5 for American Express, 4-6-4 for Diners Club), so there is no single layout to pin them to. Performs no brand detection (Visa, Mastercard, Amex...), issuer range lookup or expiration/CVV checks, only the digit count (12 to 19) and the Luhn check digit. A `number` is only accepted when it is a non-negative safe integer: anything above `Number.MAX_SAFE_INTEGER` (2^53 - 1, 16 digits) has already been rounded to a different number before the function sees it, so pass a longer PAN as a string. A value whose digits are all the same (`'0000000000000000'`) is rejected even when it passes the Luhn check, the way every other validator of this package rejects a repeated-digit document (`isValidCpf('00000000000')`, `isValidCns`, `isValidCaepf`, `isValidCei`).
+### isValidCreditCard
+
+Check if a payment card number (credit or debit) is valid using the Luhn algorithm. Only the digit count (12 to 19) and the Luhn check digit are checked. There is no brand detection (Visa, Mastercard, Amex...), issuer range lookup or expiration/CVV checks.
+
+- Accepts a string or a number, with the mask characters (whitespace, `.`, `-` and `/`) anywhere between the digits.
```javascript
import { isValidCreditCard } from '@brazilian-utils/brazilian-utils';
@@ -2248,6 +2713,7 @@ isValidCreditCard('4111111111111111'); // true (Visa test number)
isValidCreditCard('5555555555554444'); // true (Mastercard test number)
isValidCreditCard('378282246310005'); // true (American Express test number)
isValidCreditCard('4111 1111 1111 1111'); // true (spaced mask)
+isValidCreditCard('4111 - 1111 - 1111 - 1111'); // true (a run of separators between the digits)
isValidCreditCard('4111.1111/1111-1111'); // true (any of the mask characters)
isValidCreditCard('4111111111111112'); // false (bad check digit)
isValidCreditCard('0000000000000000'); // false (every digit the same, though the Luhn check passes)
@@ -2255,24 +2721,42 @@ isValidCreditCard('4111a1111b1111c1111'); // false (letters between the digits)
isValidCreditCard(4111111111111111111); // false (above 2^53 - 1, pass it as a string)
```
-## isValidRegistroProfissional
+Source: [ISO/IEC 7812-1](https://www.iso.org/standard/70484.html).
+
+## Professional registration
-Check the structure of a professional council registration number (registro/inscrição profissional). It takes a single object, typed as `IsValidRegistroProfissionalParams`, the shape `isValidBankAccount` takes: `value` is the registration number, `council` picks the issuing council (`"OAB"`, `"CRM"`, `"CRO"`, `"CRP"` or `"CRC"`) and the optional `stateCode` checks the embedded UF (ignored for `"CRP"`, whose 2 digit prefix is a regional code, not a literal UF). Anything that is not an object, and an object missing `value` or `council`, is `false`. The accepted shapes are 4 to 6 digits plus the UF for `"OAB"` and `"CRM"`, 3 to 6 digits plus the UF for `"CRO"`, a 2 digit regional code plus 4 to 6 digits for `"CRP"`, and the UF plus 6 digits, the tipo de registro and one check digit for `"CRC"`. This is a structural check only: digit counts and the UF are validated, but no check digit is computed, even for CRC, whose format includes one. A CRC registration is the UF, 6 digits, the tipo de registro (`"O"` Originário or `"P"` Provisório, which says nothing about the professional category) and the check digit, as published in the [Manual de Registro do Sistema CFC/CRCs](https://cfc.org.br/wp-content/uploads/2018/04/1_manual_registro.pdf) (item 1.1). A Registro Transferido or Secundário appends `"T"` or `"S"` and the UF of the destination CRC **after** the check digit, per that same item and [Resolução CFC nº 1.707/2023](https://www1.cfc.org.br/sisweb/SRE/docs/Res_1707.pdf), art. 5º parágrafo único: the Manual's own examples are `SP-123456/O-3 T-MG`, `TO-654321/P-8 T-SC` and `PI-111222/O-5 S-AC`. Both UFs must be real state codes, and `stateCode` is compared against the originating one. A CRP regional code has to be one of the [24 Conselhos Regionais](https://site.cfp.org.br/cfp/sistema-conselhos/conselhos-pelo-brasil/) of the CFP system, CRP-01 to CRP-24. Only the CRC shape and those CRP regional codes rest on a published source: the CFP page publishes no length for the inscription number itself, and the OAB, the CFM and the CFO publish no format at all, so the digit ranges accepted for `"CRP"`, `"OAB"`, `"CRM"` and `"CRO"` are conventional rather than normative (the OAB/SP public search field is `maxlength="7"`, and the CFM documents `300`-prefixed and `P`-suffixed CRMs, none of which these shapes express). CREA is not supported: its registration format could not be confirmed from an official, publicly documented source after the 2016 national unification (RNP).
+### isValidRegistroProfissional
+
+Check the structure of a professional council registration number (registro/inscrição profissional). Only the digit count and the UF are checked, never a check digit, even for CRC.
+
+- Takes an object (`IsValidRegistroProfissionalParams`): `value`, `council` (`"OAB"`, `"CRM"`, `"CRO"`, `"CRP"` or `"CRC"`, a `RegistroProfissionalCouncil`) and an optional `stateCode` (expected UF).
+- `"OAB"` and `"CRM"`: 4 to 6 digits plus the UF (`123456/SP`, `123456-SP`); `"CRO"`: 3 to 6 digits (`12345/SP`).
+- `"CRP"`: a 2-digit regional code (`01` to `24`) plus 4 to 6 digits (`06/12345`); `stateCode` is ignored.
+- `"CRC"`: UF, 6 digits, tipo de registro (`O` or `P`) and check digit (`SP-123456/O-3`); a transfer appends `T` or `S` and the destination UF (`SP-123456/O-3 T-MG`). `stateCode` matches the originating UF.
+- The OAB, CRM, CRO and CRP shapes are conventional (no published format). CREA is not covered.
```javascript
import { isValidRegistroProfissional } from '@brazilian-utils/brazilian-utils';
isValidRegistroProfissional({ value: '123456/SP', council: 'OAB' }); // true
isValidRegistroProfissional({ value: '123456-RJ', council: 'OAB', stateCode: 'SP' }); // false (UF mismatch)
+isValidRegistroProfissional({ value: '123456', council: 'OAB' }); // false (no UF)
isValidRegistroProfissional({ value: '06/12345', council: 'CRP' }); // true
isValidRegistroProfissional({ value: 'SP-123456/O-3', council: 'CRC' }); // true
isValidRegistroProfissional({ value: 'SP-123456/O-3 T-MG', council: 'CRC' }); // true (registro transferido)
isValidRegistroProfissional({ value: 'SP-123456/T-3', council: 'CRC' }); // false ("T" is not a tipo de registro)
```
-## isValidVin
+Source: [Manual de Registro do Sistema CFC/CRCs](https://cfc.org.br/wp-content/uploads/2018/04/1_manual_registro.pdf), [Resolução CFC nº 1.707/2023](https://www1.cfc.org.br/sisweb/SRE/docs/Res_1707.pdf), [CFP regional councils](https://site.cfp.org.br/cfp/sistema-conselhos/conselhos-pelo-brasil/).
+
+## VIN
-Check if a VIN (Vehicle Identification Number / chassi) is valid. Checks the length (17 characters), the excluded letters (`I`, `O`, `Q` are never valid; [ISO 3779:2009](https://www.iso.org/standard/52200.html) structure) and the check digit at the 9th position, with the check digit and transliteration computed per [49 CFR 565.15](https://www.ecfr.gov/current/title-49/section-565.15). That check digit is a North-American requirement (49 CFR 565.15 / SAE J853): [Resolução CONTRAN nº 968/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9682022.pdf) (which revoked Resolução CONTRAN nº 24/1998 from 1 January 2025) and ABNT NBR 6066 define the Brazilian VIN structure but do not mandate it, so many Brazilian-built VINs do not carry a matching check digit. This function is therefore a North-American-style structural check, not a universal validator of Brazilian VINs. Case-insensitive and trims surrounding whitespace. A VIN is printed as one unbroken run of 17 characters, so, unlike the documents this package masks (`isValidCpf`, `isValidCnpj`, `isValidNfeKey`), it has no group boundary to write a separator at and none is accepted: a space, `.`, `-` or `/` among the characters is rejected instead of being stripped. A value whose 17 characters are all the same (`'00000000000000000'`) is rejected even when it carries a matching check digit, the way every other validator of this package rejects a repeated-digit document.
+### isValidVin
+
+Check if a VIN (Vehicle Identification Number / chassi) is valid. This is a North-American-style structural check, not a universal validator of Brazilian VINs.
+
+- Checks the 17-character length, the excluded letters `I`, `O` and `Q`, and the check digit at position 9.
+- Brazilian rules do not mandate the check digit, so many Brazilian-built VINs fail it.
```javascript
import { isValidVin } from '@brazilian-utils/brazilian-utils';
@@ -2282,4 +2766,7 @@ isValidVin('1m8gdm9axkp042788'); // true (check digit X, lowercase)
isValidVin('1HGCM82633A004353'); // false (bad check digit)
isValidVin('00000000000000000'); // false (every character the same, though the check digit matches)
isValidVin('1HGCM8263IA004352'); // false (contains the excluded letter I)
+isValidVin('1HGCM82633A00435'); // false (16 characters)
```
+
+Source: [ISO 3779:2009](https://www.iso.org/standard/52200.html), [49 CFR 565.15](https://www.ecfr.gov/current/title-49/section-565.15) and [Resolução CONTRAN nº 968/2022](https://www.gov.br/transportes/pt-br/assuntos/transito/conteudo-contran/resolucoes/resolucao9682022.pdf).
diff --git a/scripts/llms.ts b/scripts/llms.ts
index a97d9c013..a25b1244f 100644
--- a/scripts/llms.ts
+++ b/scripts/llms.ts
@@ -225,7 +225,7 @@ function buildLlmsTxt(utils: UtilSection[], datasetUtils: string[]): string {
return `# Brazilian Utils
-> Brazilian Utils is a zero-dependency JavaScript/TypeScript library of small, focused utilities for the day-to-day problems of building software for Brazilian businesses: validating, formatting, parsing and generating documents (CPF, CNPJ, CEP, Pix, boleto, NF-e, phone numbers, license plates and more).
+> Brazilian Utils is a zero-dependency JavaScript/TypeScript library of small, focused utilities for the day-to-day problems of building software for Brazil: validating, formatting, parsing and generating CPF, CNPJ, CEP, Pix, boleto, NF-e, phone numbers, license plates and more.
The package has **zero runtime dependencies**, is fully tree-shakeable and runs on Node.js \`^20.19.0 || >=22.12.0\`, Bun, Deno and modern browsers (including a UMD \`