Skip to content

Commit fae1472

Browse files
authored
Merge pull request #469 from vicentevendramin/feat/adds-tools-for-handling-brazilian-passports
feat: adds tools for handling brazilian passports
2 parents 9ae816b + da4e356 commit fae1472

14 files changed

Lines changed: 251 additions & 0 deletions

docs/pt-br/utilities.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,47 @@ getHolidays(2024);
503503
getHolidays({ year: 2024, stateCode: 'SP' });
504504
// Inclui feriados nacionais mais feriados estaduais (ex: "Revolução Constitucionalista")
505505
```
506+
507+
## isValidPassport
508+
509+
Verifica se um número de passaporte brasileiro é válido (2 letras maiúsculas seguidas de 6 dígitos).
510+
511+
```javascript
512+
import { isValidPassport } from '@brazilian-utils/brazilian-utils';
513+
514+
isValidPassport('AB123456'); // true
515+
isValidPassport('Ab123456'); // false
516+
isValidPassport('12345678'); // false
517+
```
518+
519+
## formatPassport
520+
521+
Formata um número de passaporte brasileiro (maiúsculas, sem símbolos).
522+
523+
```javascript
524+
import { formatPassport } from '@brazilian-utils/brazilian-utils';
525+
526+
formatPassport('ab123456'); // 'AB123456'
527+
formatPassport('AB-123.456'); // 'AB123456'
528+
```
529+
530+
## generatePassport
531+
532+
Gera um número de passaporte brasileiro válido aleatoriamente.
533+
534+
```javascript
535+
import { generatePassport } from '@brazilian-utils/brazilian-utils';
536+
537+
generatePassport(); // 'RY393097'
538+
```
539+
540+
## parsePassport
541+
542+
Remove símbolos ('-', '.' e espaços) de um número de passaporte.
543+
544+
```javascript
545+
import { parsePassport } from '@brazilian-utils/brazilian-utils';
546+
547+
parsePassport('AB-123.456'); // 'AB123456'
548+
parsePassport(' AB 123 456 '); // 'AB123456'
549+
```

docs/utilities.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,47 @@ getHolidays(2024);
503503
getHolidays({ year: 2024, stateCode: 'SP' });
504504
// Includes national holidays plus state-specific holidays (e.g., "Revolução Constitucionalista")
505505
```
506+
507+
## isValidPassport
508+
509+
Check if a Brazilian passport number is valid (2 uppercase letters followed by 6 digits).
510+
511+
```javascript
512+
import { isValidPassport } from '@brazilian-utils/brazilian-utils';
513+
514+
isValidPassport('AB123456'); // true
515+
isValidPassport('Ab123456'); // false
516+
isValidPassport('12345678'); // false
517+
```
518+
519+
## formatPassport
520+
521+
Format a Brazilian passport number (uppercase, without symbols).
522+
523+
```javascript
524+
import { formatPassport } from '@brazilian-utils/brazilian-utils';
525+
526+
formatPassport('ab123456'); // 'AB123456'
527+
formatPassport('AB-123.456'); // 'AB123456'
528+
```
529+
530+
## generatePassport
531+
532+
Generate a random valid Brazilian passport number.
533+
534+
```javascript
535+
import { generatePassport } from '@brazilian-utils/brazilian-utils';
536+
537+
generatePassport(); // 'RY393097'
538+
```
539+
540+
## parsePassport
541+
542+
Remove symbols ('-', '.', and whitespaces) from a passport number.
543+
544+
```javascript
545+
import { parsePassport } from '@brazilian-utils/brazilian-utils';
546+
547+
parsePassport('AB-123.456'); // 'AB123456'
548+
parsePassport(' AB 123 456 '); // 'AB123456'
549+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { describe, expect, test } from "../_internals/test/runtime";
2+
import { formatPassport } from "./format-passport";
3+
4+
describe("formatPassport", () => {
5+
describe("should return the formatted passport", () => {
6+
test("when passport is valid", () => {
7+
expect(formatPassport("AB123456")).toBe("AB123456");
8+
});
9+
10+
test("when passport has lowercase letters", () => {
11+
expect(formatPassport("acd12736")).toBe("ACD12736");
12+
});
13+
});
14+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Formats a Brazilian passport number for display.
3+
* Converts to uppercase and removes all non-alphanumeric characters.
4+
*
5+
* @param passport - A Brazilian passport number (any case, possibly with symbols).
6+
* @returns The formatted passport number (uppercase, no symbols), or an empty string if invalid.
7+
*
8+
* @example
9+
* formatPassport("ab123456") // "AB123456"
10+
* formatPassport("AB-123.456") // "AB123456"
11+
* formatPassport("") // ""
12+
*/
13+
export const formatPassport = (passport: string): string => {
14+
if (!passport || typeof passport !== "string") return "";
15+
return passport.toUpperCase().replace(/[^A-Z0-9]/g, "");
16+
};

src/generate-passport/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const LETTERS_LENGTH = 2;
2+
export const DIGITS_LENGTH = 6;
3+
export const ALPHABET_LENGTH = 26;
4+
export const CHAR_CODE_A = 65;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { describe, expect, test } from "../_internals/test/runtime";
2+
import { isValidPassport } from "../is-valid-passport/is-valid-passport";
3+
import { generatePassport } from "./generate-passport";
4+
5+
describe("generatePassport", () => {
6+
test("should always generate a valid passport", () => {
7+
for (let i = 0; i < 100; i++) {
8+
expect(isValidPassport(generatePassport())).toBe(true);
9+
}
10+
});
11+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { generateRandomNumber } from "../_internals/generate-random-number/generate-random-number";
2+
import { ALPHABET_LENGTH, CHAR_CODE_A, DIGITS_LENGTH, LETTERS_LENGTH } from "./constants";
3+
4+
/**
5+
* Generates a random valid Brazilian passport number.
6+
*
7+
* @returns A random valid passport number string (e.g. "RY393097").
8+
*
9+
* @example
10+
* generatePassport() // "RY393097"
11+
* generatePassport() // "ZS840088"
12+
*/
13+
export const generatePassport = (): string => {
14+
const letters = Array.from({ length: LETTERS_LENGTH }, () =>
15+
String.fromCharCode(CHAR_CODE_A + Math.floor(Math.random() * ALPHABET_LENGTH)),
16+
).join("");
17+
18+
const digits = generateRandomNumber(DIGITS_LENGTH);
19+
20+
return `${letters}${digits}`;
21+
};

src/index.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const PUBLIC = [
2727
"parseCpf",
2828
"parseCurrency",
2929
"parsePhone",
30+
"isValidPassport",
31+
"generatePassport",
32+
"parsePassport",
33+
"formatPassport",
3034
"formatPis",
3135
"parsePis",
3236
"parseProcessoJuridico",

src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { type FormatCepOptions, formatCep } from "./format-cep/format-cep";
44
export { type FormatCnpjOptions, formatCnpj } from "./format-cnpj/format-cnpj";
55
export { type FormatCpfOptions, formatCpf } from "./format-cpf/format-cpf";
66
export { type FormatCurrencyOptions, formatCurrency } from "./format-currency/format-currency";
7+
export { formatPassport } from "./format-passport/format-passport";
78
export { type FormatPhoneOptions, formatPhone } from "./format-phone/format-phone";
89
export { type FormatPisOptions, formatPis } from "./format-pis/format-pis";
910
export {
@@ -13,6 +14,7 @@ export {
1314
export { generateBoleto } from "./generate-boleto/generate-boleto";
1415
export { generateCnpj } from "./generate-cnpj/generate-cnpj";
1516
export { generateCpf } from "./generate-cpf/generate-cpf";
17+
export { generatePassport } from "./generate-passport/generate-passport";
1618
export {
1719
GetAddressInfoByCepError,
1820
GetAddressInfoByCepNotFoundError,
@@ -41,6 +43,7 @@ export {
4143
type IsValidMobilePhoneOptions,
4244
isValidMobilePhone,
4345
} from "./is-valid-mobile-phone/is-valid-mobile-phone";
46+
export { isValidPassport } from "./is-valid-passport/is-valid-passport";
4447
export { type IsValidPhoneOptions, isValidPhone } from "./is-valid-phone/is-valid-phone";
4548
export { isValidPis } from "./is-valid-pis/is-valid-pis";
4649
export { isValidProcessoJuridico } from "./is-valid-processo-juridico/is-valid-processo-juridico";
@@ -50,6 +53,7 @@ export { parseCep } from "./parse-cep/parse-cep";
5053
export { parseCnpj } from "./parse-cnpj/parse-cnpj";
5154
export { parseCpf } from "./parse-cpf/parse-cpf";
5255
export { parseCurrency } from "./parse-currency/parse-currency";
56+
export { parsePassport } from "./parse-passport/parse-passport";
5357
export { parsePhone } from "./parse-phone/parse-phone";
5458
export { parsePis } from "./parse-pis/parse-pis";
5559
export { parseProcessoJuridico } from "./parse-processo-juridico/parse-processo-juridico";

src/is-valid-passport/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const PASSPORT_REGEX = /^[A-Z]{2}[0-9]{6}$/;

0 commit comments

Comments
 (0)