Skip to content
44 changes: 44 additions & 0 deletions docs/pt-br/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,47 @@ getHolidays(2024);
getHolidays({ year: 2024, stateCode: 'SP' });
// Inclui feriados nacionais mais feriados estaduais (ex: "Revolução Constitucionalista")
```

## isValidPassport

Verifica se um número de passaporte brasileiro é válido (2 letras maiúsculas seguidas de 6 dígitos).

```javascript
import { isValidPassport } from '@brazilian-utils/brazilian-utils';

isValidPassport('AB123456'); // true
isValidPassport('Ab123456'); // false
isValidPassport('12345678'); // false
```

## formatPassport

Formata um número de passaporte brasileiro (maiúsculas, sem símbolos).

```javascript
import { formatPassport } from '@brazilian-utils/brazilian-utils';

formatPassport('ab123456'); // 'AB123456'
formatPassport('AB-123.456'); // 'AB123456'
```

## generatePassport

Gera um número de passaporte brasileiro válido aleatoriamente.

```javascript
import { generatePassport } from '@brazilian-utils/brazilian-utils';

generatePassport(); // 'RY393097'
```

## parsePassport

Remove símbolos ('-', '.' e espaços) de um número de passaporte.

```javascript
import { parsePassport } from '@brazilian-utils/brazilian-utils';

parsePassport('AB-123.456'); // 'AB123456'
parsePassport(' AB 123 456 '); // 'AB123456'
```
44 changes: 44 additions & 0 deletions docs/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,47 @@ getHolidays(2024);
getHolidays({ year: 2024, stateCode: 'SP' });
// Includes national holidays plus state-specific holidays (e.g., "Revolução Constitucionalista")
```

## isValidPassport

Check if a Brazilian passport number is valid (2 uppercase letters followed by 6 digits).

```javascript
import { isValidPassport } from '@brazilian-utils/brazilian-utils';

isValidPassport('AB123456'); // true
isValidPassport('Ab123456'); // false
isValidPassport('12345678'); // false
```

## formatPassport

Format a Brazilian passport number (uppercase, without symbols).

```javascript
import { formatPassport } from '@brazilian-utils/brazilian-utils';

formatPassport('ab123456'); // 'AB123456'
formatPassport('AB-123.456'); // 'AB123456'
```

## generatePassport

Generate a random valid Brazilian passport number.

```javascript
import { generatePassport } from '@brazilian-utils/brazilian-utils';

generatePassport(); // 'RY393097'
```

## parsePassport

Remove symbols ('-', '.', and whitespaces) from a passport number.

```javascript
import { parsePassport } from '@brazilian-utils/brazilian-utils';

parsePassport('AB-123.456'); // 'AB123456'
parsePassport(' AB 123 456 '); // 'AB123456'
```
14 changes: 14 additions & 0 deletions src/format-passport/format-passport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { describe, expect, test } from "../_internals/test/runtime";
import { formatPassport } from "./format-passport";

describe("formatPassport", () => {
describe("should return the formatted passport", () => {
test("when passport is valid", () => {
expect(formatPassport("AB123456")).toBe("AB123456");
});

test("when passport has lowercase letters", () => {
expect(formatPassport("acd12736")).toBe("ACD12736");
});
});
});
Comment on lines +4 to +14
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tem como tu tirar o mock aqui?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removi o mock e alterei o formatPassport

16 changes: 16 additions & 0 deletions src/format-passport/format-passport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Formats a Brazilian passport number for display.
* Converts to uppercase and removes all non-alphanumeric characters.
*
* @param passport - A Brazilian passport number (any case, possibly with symbols).
* @returns The formatted passport number (uppercase, no symbols), or an empty string if invalid.
*
* @example
* formatPassport("ab123456") // "AB123456"
* formatPassport("AB-123.456") // "AB123456"
* formatPassport("") // ""
*/
export const formatPassport = (passport: string): string => {
if (!passport || typeof passport !== "string") return "";
return passport.toUpperCase().replace(/[^A-Z0-9]/g, "");
};
4 changes: 4 additions & 0 deletions src/generate-passport/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const LETTERS_LENGTH = 2;
export const DIGITS_LENGTH = 6;
export const ALPHABET_LENGTH = 26;
export const CHAR_CODE_A = 65;
11 changes: 11 additions & 0 deletions src/generate-passport/generate-passport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { describe, expect, test } from "../_internals/test/runtime";
import { isValidPassport } from "../is-valid-passport/is-valid-passport";
import { generatePassport } from "./generate-passport";

describe("generatePassport", () => {
test("should always generate a valid passport", () => {
for (let i = 0; i < 100; i++) {
expect(isValidPassport(generatePassport())).toBe(true);
}
});
});
21 changes: 21 additions & 0 deletions src/generate-passport/generate-passport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { generateRandomNumber } from "../_internals/generate-random-number/generate-random-number";
import { ALPHABET_LENGTH, CHAR_CODE_A, DIGITS_LENGTH, LETTERS_LENGTH } from "./constants";

/**
* Generates a random valid Brazilian passport number.
*
* @returns A random valid passport number string (e.g. "RY393097").
*
* @example
* generatePassport() // "RY393097"
* generatePassport() // "ZS840088"
*/
export const generatePassport = (): string => {
const letters = Array.from({ length: LETTERS_LENGTH }, () =>
String.fromCharCode(CHAR_CODE_A + Math.floor(Math.random() * ALPHABET_LENGTH)),
).join("");

const digits = generateRandomNumber(DIGITS_LENGTH);

return `${letters}${digits}`;
};
4 changes: 4 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const PUBLIC = [
"parseCpf",
"parseCurrency",
"parsePhone",
"isValidPassport",
"generatePassport",
"parsePassport",
"formatPassport",
"formatPis",
"parsePis",
"parseProcessoJuridico",
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { type FormatCepOptions, formatCep } from "./format-cep/format-cep";
export { type FormatCnpjOptions, formatCnpj } from "./format-cnpj/format-cnpj";
export { type FormatCpfOptions, formatCpf } from "./format-cpf/format-cpf";
export { type FormatCurrencyOptions, formatCurrency } from "./format-currency/format-currency";
export { formatPassport } from "./format-passport/format-passport";
export { type FormatPhoneOptions, formatPhone } from "./format-phone/format-phone";
export { type FormatPisOptions, formatPis } from "./format-pis/format-pis";
export {
Expand All @@ -13,6 +14,7 @@ export {
export { generateBoleto } from "./generate-boleto/generate-boleto";
export { generateCnpj } from "./generate-cnpj/generate-cnpj";
export { generateCpf } from "./generate-cpf/generate-cpf";
export { generatePassport } from "./generate-passport/generate-passport";
export {
GetAddressInfoByCepError,
GetAddressInfoByCepNotFoundError,
Expand Down Expand Up @@ -41,6 +43,7 @@ export {
type IsValidMobilePhoneOptions,
isValidMobilePhone,
} from "./is-valid-mobile-phone/is-valid-mobile-phone";
export { isValidPassport } from "./is-valid-passport/is-valid-passport";
export { type IsValidPhoneOptions, isValidPhone } from "./is-valid-phone/is-valid-phone";
export { isValidPis } from "./is-valid-pis/is-valid-pis";
export { isValidProcessoJuridico } from "./is-valid-processo-juridico/is-valid-processo-juridico";
Expand All @@ -50,6 +53,7 @@ export { parseCep } from "./parse-cep/parse-cep";
export { parseCnpj } from "./parse-cnpj/parse-cnpj";
export { parseCpf } from "./parse-cpf/parse-cpf";
export { parseCurrency } from "./parse-currency/parse-currency";
export { parsePassport } from "./parse-passport/parse-passport";
export { parsePhone } from "./parse-phone/parse-phone";
export { parsePis } from "./parse-pis/parse-pis";
export { parseProcessoJuridico } from "./parse-processo-juridico/parse-processo-juridico";
Expand Down
1 change: 1 addition & 0 deletions src/is-valid-passport/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const PASSPORT_REGEX = /^[A-Z]{2}[0-9]{6}$/;
25 changes: 25 additions & 0 deletions src/is-valid-passport/is-valid-passport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, expect, test } from "../_internals/test/runtime";
import { isValidPassport } from "./is-valid-passport";

describe("isValidPassport", () => {
describe("should return false", () => {
test("when passport is not a string", () => {
expect(isValidPassport(1 as unknown as string)).toBe(false);
});

test("when passport length is different from 8", () => {
expect(isValidPassport("1")).toBe(false);
});

test("when passport does not match the expected format", () => {
expect(isValidPassport("1112223334-")).toBe(false);
});
});

describe("should return true", () => {
test("when passport is valid", () => {
expect(isValidPassport("AA111111")).toBe(true);
expect(isValidPassport("CL125167")).toBe(true);
});
});
});
22 changes: 22 additions & 0 deletions src/is-valid-passport/is-valid-passport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PASSPORT_REGEX } from "./constants";

/**
* Checks if a Brazilian passport number is valid.
* To be considered valid, the input must be a string containing exactly two
* alphabetical characters followed by exactly six numerical digits.
* This function does not verify if the input is a real passport number,
* as there are no checksums for the Brazilian passport.
*
* @param passport - The string containing the passport number to be checked.
* @returns True if the passport number is valid (2 letters followed by 6 digits).
*
* @example
* isValidPassport("Ab123456") // false - must be uppercase
* isValidPassport("AB123456") // true
* isValidPassport("12345678") // false
* isValidPassport("DC-221345") // false
*/
export const isValidPassport = (passport: string | number): boolean => {
if (passport === null || passport === undefined) return false;
return PASSPORT_REGEX.test(String(passport));
};
26 changes: 26 additions & 0 deletions src/parse-passport/parse-passport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, test } from "../_internals/test/runtime";
import { parsePassport } from "./parse-passport";

describe("parsePassport", () => {
describe("should return the string without symbols", () => {
test("when there are no symbols, returns the same string", () => {
expect(parsePassport("Ab123456")).toBe("Ab123456");
});

test("when there are spaces", () => {
expect(parsePassport(" AB 123 456 ")).toBe("AB123456");
});

test("when there are dashes", () => {
expect(parsePassport("-AB1-23-4-56-")).toBe("AB123456");
});

test("when there are dots", () => {
expect(parsePassport(".AB.1.23.456.")).toBe("AB123456");
});

test("when there are multiple symbols", () => {
expect(parsePassport(".A B.1.2-3.45 -. 6.")).toBe("AB123456");
});
});
});
15 changes: 15 additions & 0 deletions src/parse-passport/parse-passport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Removes symbols ('-', '.', and whitespaces) from a passport number.
*
* @param passport - The string containing a passport number.
* @returns The passport number with dashes, dots, and whitespaces removed.
*
* @example
* parsePassport("Ab123456") // "Ab123456"
* parsePassport("Ab-123456") // "Ab123456"
* parsePassport("Ab -. 123456") // "Ab123456"
*/
export const parsePassport = (passport: string): string => {
if (!passport || typeof passport !== "string") return "";
return passport.replace(/[^a-zA-Z0-9]/g, "");
};
Loading