Feat/joi integration - #12
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds Joi validation library integration to the br-docs package, enabling schema-based validation of Brazilian documents. It also fixes the CNH validation algorithm and adds the Nis export.
Changes:
- Added a comprehensive Joi extension for validating Brazilian documents (CPF, CNPJ, NIS, CNH, CEP, phone, PIX, boleto, celular)
- Fixed CNH validation algorithm to correctly validate Brazilian driver's licenses
- Added documentation for the Joi integration
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/joi.ts | New Joi extension factory implementing document validation rules for Brazilian documents |
| src/index.ts | Added Nis export and a duplicate incomplete validator (needs review) |
| src/cnh.ts | Fixed CNH validation algorithm with correct check digit calculation |
| src/tests/joi.test.ts | Added comprehensive tests for the Joi extension |
| src/tests/cnh.test.ts | Updated test with a valid CNH number matching the new algorithm |
| package.json | Added Joi as optional peer dependency and updated package exports |
| package-lock.json | Added Joi and its dependencies to lock file |
| docs/EXTENSOES/README.md | New documentation section for extensions |
| docs/EXTENSOES/JOI.md | Comprehensive documentation for the Joi integration |
| SUMMARY.md | Added references to the new extensions documentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import type { ExtensionFactory } from "joi"; | ||
|
|
||
| import { Cpf } from "./cpf"; | ||
| import { Cnpj } from "./cnpj"; | ||
| import { Nis } from "./nis"; | ||
| import { Cnh } from "./cnh"; | ||
| import { Cep } from "./cep"; | ||
| import { Telefone } from "./telefone"; | ||
| import { Pix } from "./pix"; | ||
| import { Boleto } from "./boleto"; | ||
| import { Celular } from "./celular"; | ||
|
|
||
| const validator: ExtensionFactory = (joi) => ({ | ||
| type: "document", | ||
| base: joi.string(), | ||
| messages: { | ||
| "document.cpf": "CPF inválido", | ||
| "document.cnpj": "CNPJ inválido", | ||
| "document.nis": "NIS inválido", | ||
| "document.cnh": "CNH inválida", | ||
| "document.cep": "CEP inválido", | ||
| "document.phone": "Telefone inválido", | ||
| "document.uuid": "UUID inválido", | ||
| "document.pix": "Chave PIX inválida", | ||
| "document.boleto": "Boleto inválido", | ||
| "document.celular": "Celular inválido", | ||
| }, | ||
| rules: { | ||
| cpf: { | ||
| validate: (value, helpers) => | ||
| Cpf.isValid(value) ? value : helpers.error("document.cpf"), | ||
| }, | ||
| cnpj: { | ||
| validate: (value, helpers) => | ||
| Cnpj.isValid(value) ? value : helpers.error("document.cnpj"), | ||
| }, | ||
| nis: { | ||
| validate: (value, helpers) => | ||
| Nis.isValid(value) ? value : helpers.error("document.nis"), | ||
| }, | ||
| cnh: { | ||
| validate: (value, helpers) => | ||
| Cnh.isValid(value) ? value : helpers.error("document.cnh"), | ||
| }, | ||
| cep: { | ||
| validate: (value, helpers) => | ||
| Cep.isValid(value) ? value : helpers.error("document.cep"), | ||
| }, | ||
| phone: { | ||
| validate: (value, helpers) => | ||
| Telefone.isValid(value) ? value : helpers.error("document.phone"), | ||
| }, | ||
| pix: { | ||
| validate: (value, helpers) => | ||
| Pix.isValid(value) ? value : helpers.error("document.pix"), | ||
| }, | ||
| boleto: { | ||
| validate: (value, helpers) => | ||
| Boleto.isValid(value) ? value : helpers.error("document.boleto"), | ||
| }, | ||
| celular: { | ||
| validate: (value, helpers) => | ||
| Celular.isValid(value) ? value : helpers.error("document.celular"), | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| export default validator; |
There was a problem hiding this comment.
The validator extension defines a message for "document.uuid" but is missing the corresponding uuid rule implementation in the rules object. The Uuid class also needs to be imported at the top of the file. Add a uuid rule similar to the other validators.
|
|
||
| export const validator = (joi: any) => ({ | ||
| type: "document", | ||
| base: joi.string(), | ||
| messages: { | ||
| "document.cpf": "CPF inválido", | ||
| "document.cnpj": "CNPJ inválido", | ||
| }, | ||
| rules: { | ||
| cpf: { | ||
| validate(value: any, helpers: any, args: any, options: any) { | ||
| if (!Cpf.isValid(value)) { | ||
| return helpers.error("document.cpf"); | ||
| } | ||
|
|
||
| return value; | ||
| }, | ||
| }, | ||
| cnpj: { | ||
| validate(value: any, helpers: any, args: any, options: any) { | ||
| if (!Cnpj.isValid(value)) { | ||
| return helpers.error("document.cnpj"); | ||
| } | ||
|
|
||
| return value; | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| export default validator; |
There was a problem hiding this comment.
This validator export in the main index file duplicates the Joi extension functionality from src/joi.ts but is incomplete (only supports CPF and CNPJ). This creates confusion about which validator to use and maintenance burden. Consider removing this incomplete validator from index.ts since a complete, well-structured Joi extension is now available in src/joi.ts and exported via package.json exports.
| export const validator = (joi: any) => ({ | |
| type: "document", | |
| base: joi.string(), | |
| messages: { | |
| "document.cpf": "CPF inválido", | |
| "document.cnpj": "CNPJ inválido", | |
| }, | |
| rules: { | |
| cpf: { | |
| validate(value: any, helpers: any, args: any, options: any) { | |
| if (!Cpf.isValid(value)) { | |
| return helpers.error("document.cpf"); | |
| } | |
| return value; | |
| }, | |
| }, | |
| cnpj: { | |
| validate(value: any, helpers: any, args: any, options: any) { | |
| if (!Cnpj.isValid(value)) { | |
| return helpers.error("document.cnpj"); | |
| } | |
| return value; | |
| }, | |
| }, | |
| }, | |
| }); | |
| export default validator; |
| it("cep / phone / celular / uuid / pix", () => { | ||
| expectOk(Joi.document().cep(), "01001-000"); | ||
| expectOk(Joi.document().phone(), "1133334444"); | ||
| expectOk(Joi.document().celular(), "11999998888"); | ||
| expectOk(Joi.document().uuid(), "550e8400-e29b-41d4-a716-446655440000"); |
There was a problem hiding this comment.
The test expects Joi.document().uuid() to work, but the uuid validation rule is not implemented in the validator extension (src/joi.ts). This test will fail at runtime. The uuid rule needs to be added to src/joi.ts before this test can pass.
| it("cep / phone / celular / uuid / pix", () => { | |
| expectOk(Joi.document().cep(), "01001-000"); | |
| expectOk(Joi.document().phone(), "1133334444"); | |
| expectOk(Joi.document().celular(), "11999998888"); | |
| expectOk(Joi.document().uuid(), "550e8400-e29b-41d4-a716-446655440000"); | |
| it("cep / phone / celular / pix", () => { | |
| expectOk(Joi.document().cep(), "01001-000"); | |
| expectOk(Joi.document().phone(), "1133334444"); | |
| expectOk(Joi.document().celular(), "11999998888"); |
| it("cep / phone / celular / uuid / pix", () => { | ||
| expectOk(Joi.document().cep(), "01001-000"); | ||
| expectOk(Joi.document().phone(), "1133334444"); | ||
| expectOk(Joi.document().celular(), "11999998888"); | ||
| expectOk(Joi.document().uuid(), "550e8400-e29b-41d4-a716-446655440000"); | ||
| expectOk(Joi.document().pix(), "a@b.com"); | ||
| }); |
There was a problem hiding this comment.
The test case only validates successful validation for cep, phone, celular, uuid, and pix. Consider adding error case tests (using expectErr) for these validators to ensure proper error handling and messages, similar to how cpf, cnpj, nis, cnh, and boleto are tested.
No description provided.