@br-validators/cli
Advanced tools
+236
-24
@@ -9,12 +9,11 @@ #!/usr/bin/env node | ||
| // src/commands/cep.ts | ||
| // src/commands/brcode.ts | ||
| import { | ||
| CEP_OFFICIAL_SOURCE_URL, | ||
| formatCep, | ||
| stripCep, | ||
| validateCep | ||
| BRCODE_OFFICIAL_SOURCE_URL, | ||
| parseBrCode, | ||
| validateBrCode | ||
| } from "@br-validators/core"; | ||
| // src/constants.ts | ||
| var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"]; | ||
| var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "telefone", "brcode", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"]; | ||
| var EXIT = { | ||
@@ -26,2 +25,84 @@ OK: 0, | ||
| // src/commands/brcode.ts | ||
| function resolveInput(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
| if (!input) { | ||
| return null; | ||
| } | ||
| return input; | ||
| } | ||
| function printBrCodeResult(result, options, io = { stdout: [], stderr: [] }) { | ||
| if (options.json) { | ||
| io.stdout.push( | ||
| JSON.stringify( | ||
| result.ok ? { | ||
| ok: true, | ||
| value: result.value, | ||
| format: result.format, | ||
| merchantName: result.merchantName, | ||
| merchantCity: result.merchantCity, | ||
| ...result.amount ? { amount: result.amount } : {}, | ||
| ...result.txid ? { txid: result.txid } : {}, | ||
| ...result.pixKey ? { pixKey: result.pixKey, pixKeyType: result.pixKeyType } : {}, | ||
| ...result.pixInitiationUrl ? { pixInitiationUrl: result.pixInitiationUrl } : {}, | ||
| ...options.source ? { source: options.source } : {} | ||
| } : { ok: false, code: result.code, message: result.message }, | ||
| null, | ||
| 2 | ||
| ) | ||
| ); | ||
| return result.ok ? EXIT.OK : EXIT.INVALID; | ||
| } | ||
| if (options.quiet) { | ||
| return result.ok ? EXIT.OK : EXIT.INVALID; | ||
| } | ||
| if (result.ok) { | ||
| io.stdout.push("valid: yes"); | ||
| io.stdout.push(`merchantName: ${result.merchantName}`); | ||
| io.stdout.push(`merchantCity: ${result.merchantCity}`); | ||
| if (result.amount) { | ||
| io.stdout.push(`amount: ${result.amount}`); | ||
| } | ||
| if (result.txid) { | ||
| io.stdout.push(`txid: ${result.txid}`); | ||
| } | ||
| if (result.pixKey) { | ||
| io.stdout.push(`pixKey: ${result.pixKey}`); | ||
| io.stdout.push(`pixKeyType: ${result.pixKeyType}`); | ||
| } | ||
| if (result.pixInitiationUrl) { | ||
| io.stdout.push(`pixInitiationUrl: ${result.pixInitiationUrl}`); | ||
| } | ||
| if (options.source) { | ||
| io.stdout.push(`source: ${options.source}`); | ||
| } | ||
| return EXIT.OK; | ||
| } | ||
| io.stderr.push("valid: no"); | ||
| io.stderr.push(`code: ${result.code}`); | ||
| io.stderr.push(`message: ${result.message}`); | ||
| return EXIT.INVALID; | ||
| } | ||
| function runBrCodeCommand(action, input, options, io = { stdout: [], stderr: [] }) { | ||
| const source = options.source ? BRCODE_OFFICIAL_SOURCE_URL : void 0; | ||
| const result = action === "validate" ? validateBrCode(input) : parseBrCode(input); | ||
| return printBrCodeResult(result, { json: options.json, quiet: options.quiet, source }, io); | ||
| } | ||
| function runBrCode(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput(value, options.file); | ||
| if (input === null) { | ||
| io.stderr.push("Missing BR Code payload. Pass an argument or use --file."); | ||
| return EXIT.USAGE; | ||
| } | ||
| return runBrCodeCommand(action, input, options, io); | ||
| } | ||
| // src/commands/cep.ts | ||
| import { | ||
| CEP_OFFICIAL_SOURCE_URL, | ||
| formatCep, | ||
| stripCep, | ||
| validateCep | ||
| } from "@br-validators/core"; | ||
| // src/output.ts | ||
@@ -86,3 +167,3 @@ function printValidation(result, options, io = { stdout: [], stderr: [] }) { | ||
| // src/commands/cep.ts | ||
| function resolveInput(value, fileContent) { | ||
| function resolveInput2(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -111,3 +192,3 @@ if (!input) { | ||
| function runCep(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput(value, options.file); | ||
| const input = resolveInput2(value, options.file); | ||
| if (input === null) { | ||
@@ -120,2 +201,75 @@ io.stderr.push("Missing CEP value. Pass an argument or use --file."); | ||
| // src/commands/telefone.ts | ||
| import { | ||
| TELEFONE_OFFICIAL_SOURCE_URL, | ||
| formatTelefone, | ||
| stripTelefone, | ||
| validateTelefone | ||
| } from "@br-validators/core"; | ||
| function resolveInput3(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
| if (!input) { | ||
| return null; | ||
| } | ||
| return input; | ||
| } | ||
| function printTelefoneValidation(result, options, io = { stdout: [], stderr: [] }) { | ||
| if (options.json) { | ||
| io.stdout.push( | ||
| JSON.stringify( | ||
| result.ok ? { | ||
| ok: true, | ||
| value: result.value, | ||
| tipo: result.tipo, | ||
| format: result.format, | ||
| ...options.source ? { source: options.source } : {} | ||
| } : { ok: false, code: result.code, message: result.message }, | ||
| null, | ||
| 2 | ||
| ) | ||
| ); | ||
| return result.ok ? EXIT.OK : EXIT.INVALID; | ||
| } | ||
| if (options.quiet) { | ||
| return result.ok ? EXIT.OK : EXIT.INVALID; | ||
| } | ||
| if (result.ok) { | ||
| io.stdout.push(`valid: yes (${result.tipo})`); | ||
| io.stdout.push(`value: ${result.value}`); | ||
| io.stdout.push(`format: ${result.format}`); | ||
| if (options.source) { | ||
| io.stdout.push(`source: ${options.source}`); | ||
| } | ||
| return EXIT.OK; | ||
| } | ||
| io.stderr.push("valid: no"); | ||
| io.stderr.push(`code: ${result.code}`); | ||
| io.stderr.push(`message: ${result.message}`); | ||
| return EXIT.INVALID; | ||
| } | ||
| function runTelefoneCommand(action, input, options, io = { stdout: [], stderr: [] }) { | ||
| const source = options.source ? TELEFONE_OFFICIAL_SOURCE_URL : void 0; | ||
| switch (action) { | ||
| case "validate": | ||
| return printTelefoneValidation(validateTelefone(input), { json: options.json, quiet: options.quiet, source }, io); | ||
| case "format": | ||
| return printFormat(formatTelefone(input), { json: options.json, quiet: options.quiet }, io); | ||
| case "strip": | ||
| return printStrip(stripTelefone(input), { json: options.json }, io); | ||
| default: { | ||
| const _exhaustive = action; | ||
| io.stderr.push(`Unknown action: ${_exhaustive}`); | ||
| return EXIT.USAGE; | ||
| } | ||
| } | ||
| } | ||
| function runTelefone(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput3(value, options.file); | ||
| if (input === null) { | ||
| io.stderr.push("Missing telephone value. Pass an argument or use --file."); | ||
| return EXIT.USAGE; | ||
| } | ||
| return runTelefoneCommand(action, input, options, io); | ||
| } | ||
| // src/commands/cnpj.ts | ||
@@ -128,3 +282,3 @@ import { | ||
| } from "@br-validators/core"; | ||
| function resolveInput2(value, fileContent) { | ||
| function resolveInput4(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -153,3 +307,3 @@ if (!input) { | ||
| function runCnpj(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput2(value, options.file); | ||
| const input = resolveInput4(value, options.file); | ||
| if (input === null) { | ||
@@ -169,3 +323,3 @@ io.stderr.push("Missing CNPJ value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput3(value, fileContent) { | ||
| function resolveInput5(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -194,3 +348,3 @@ if (!input) { | ||
| function runCpf(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput3(value, options.file); | ||
| const input = resolveInput5(value, options.file); | ||
| if (input === null) { | ||
@@ -211,3 +365,3 @@ io.stderr.push("Missing CPF value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput4(value, fileContent) { | ||
| function resolveInput6(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -238,3 +392,3 @@ if (!input) { | ||
| function runPlaca(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput4(value, options.file); | ||
| const input = resolveInput6(value, options.file); | ||
| if (input === null) { | ||
@@ -254,3 +408,3 @@ io.stderr.push("Missing placa value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput5(value, fileContent) { | ||
| function resolveInput7(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -279,3 +433,3 @@ if (!input) { | ||
| function runPisPasep(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput5(value, options.file); | ||
| const input = resolveInput7(value, options.file); | ||
| if (input === null) { | ||
@@ -295,3 +449,3 @@ io.stderr.push("Missing PIS/PASEP value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput6(value, fileContent) { | ||
| function resolveInput8(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -371,3 +525,3 @@ if (!input) { | ||
| function runPix(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput6(value, options.file); | ||
| const input = resolveInput8(value, options.file); | ||
| if (input === null) { | ||
@@ -391,3 +545,3 @@ io.stderr.push("Missing PIX key value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput7(value, fileContent) { | ||
| function resolveInput9(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -516,3 +670,3 @@ if (!input) { | ||
| function runBoleto(action, value, options, direction, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput7(value, options.file); | ||
| const input = resolveInput9(value, options.file); | ||
| if (input === null) { | ||
@@ -533,3 +687,3 @@ io.stderr.push("Missing boleto value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput8(value, fileContent) { | ||
| function resolveInput10(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -610,3 +764,3 @@ if (!input) { | ||
| function runCartao(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput8(value, options.file); | ||
| const input = resolveInput10(value, options.file); | ||
| if (input === null) { | ||
@@ -627,3 +781,3 @@ io.stderr.push("Missing credit card PAN value. Pass an argument or use --file."); | ||
| } from "@br-validators/core"; | ||
| function resolveInput9(value, fileContent) { | ||
| function resolveInput11(value, fileContent) { | ||
| const input = value ?? fileContent?.trim(); | ||
@@ -709,3 +863,3 @@ if (!input) { | ||
| function runIe(action, value, options, io = { stdout: [], stderr: [] }) { | ||
| const input = resolveInput9(value, options.file); | ||
| const input = resolveInput11(value, options.file); | ||
| if (input === null) { | ||
@@ -801,2 +955,23 @@ io.stderr.push("Missing IE value. Pass an argument or use --file."); | ||
| } | ||
| function handleTelefoneCli(action, value, opts, io = { stdout: [], stderr: [] }) { | ||
| let fileContent; | ||
| if (opts.file) { | ||
| const content = readInputFile(opts.file, io); | ||
| if (content === null) { | ||
| return EXIT.USAGE; | ||
| } | ||
| fileContent = content; | ||
| } | ||
| return runTelefone( | ||
| action, | ||
| value, | ||
| { | ||
| json: Boolean(opts.json), | ||
| quiet: Boolean(opts.quiet), | ||
| source: Boolean(opts.source), | ||
| file: fileContent | ||
| }, | ||
| io | ||
| ); | ||
| } | ||
| function handlePlacaCli(action, value, opts, io = { stdout: [], stderr: [] }) { | ||
@@ -931,2 +1106,23 @@ let fileContent; | ||
| } | ||
| function handleBrCodeCli(action, value, opts, io = { stdout: [], stderr: [] }) { | ||
| let fileContent; | ||
| if (opts.file) { | ||
| const content = readInputFile(opts.file, io); | ||
| if (content === null) { | ||
| return EXIT.USAGE; | ||
| } | ||
| fileContent = content; | ||
| } | ||
| return runBrCode( | ||
| action, | ||
| value, | ||
| { | ||
| json: Boolean(opts.json), | ||
| quiet: Boolean(opts.quiet), | ||
| source: Boolean(opts.source), | ||
| file: fileContent | ||
| }, | ||
| io | ||
| ); | ||
| } | ||
| function handleIeCli(action, value, opts, io = { stdout: [], stderr: [] }) { | ||
@@ -992,2 +1188,18 @@ let fileContent; | ||
| } | ||
| const telefone = program.command("telefone").description("Telefone \u2014 Brazilian fixo/celular (Anatel DDD)"); | ||
| for (const action of ["validate", "format", "strip"]) { | ||
| telefone.command(action).description(`${action} a Brazilian telephone number`).argument("[value]", "Telephone value (raw or masked)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL (validate only)").option("-f, --file <path>", "Read value from file").action((value, opts) => { | ||
| const io = { stdout: [], stderr: [] }; | ||
| process.exitCode = handleTelefoneCli(action, value, opts, io); | ||
| writeCliIo(io); | ||
| }); | ||
| } | ||
| const brcode = program.command("brcode").description("BR Code \u2014 PIX QR payload (Bacen EMV TLV)"); | ||
| for (const action of ["parse", "validate"]) { | ||
| brcode.command(action).description(`${action} a BR Code payload`).argument("[value]", "BR Code payload (Pix Copia e Cola)").option("--json", "JSON output").option("-q, --quiet", "Exit code only").option("--source", "Include official source URL").option("-f, --file <path>", "Read value from file").action((value, opts) => { | ||
| const io = { stdout: [], stderr: [] }; | ||
| process.exitCode = handleBrCodeCli(action, value, opts, io); | ||
| writeCliIo(io); | ||
| }); | ||
| } | ||
| const placa = program.command("placa").description("Placa \u2014 legacy + Mercosul (CONTRAN)"); | ||
@@ -994,0 +1206,0 @@ for (const action of ["validate", "format", "strip", "convert"]) { |
+4
-2
| { | ||
| "name": "@br-validators/cli", | ||
| "version": "0.10.0-alpha.1", | ||
| "version": "0.11.0-alpha.0", | ||
| "description": "Terminal CLI for Brazilian document validation — CPF, CNPJ, CEP, IE, PIX, boleto, and more", | ||
@@ -32,3 +32,3 @@ "license": "MIT", | ||
| "commander": "^13.1.0", | ||
| "@br-validators/core": "0.10.0-alpha.0" | ||
| "@br-validators/core": "0.11.0-alpha.0" | ||
| }, | ||
@@ -48,2 +48,4 @@ "devDependencies": { | ||
| "build": "tsup", | ||
| "pretest": "pnpm run build", | ||
| "pretest:coverage": "pnpm run build", | ||
| "pretypecheck": "pnpm --filter @br-validators/core build", | ||
@@ -50,0 +52,0 @@ "test": "vitest run", |
48030
18.02%1269
19.94%+ Added
- Removed