@br-validators/cli 0.10.0-alpha.0 → 0.11.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +236 -25
  3. package/package.json +10 -7
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Terminal CLI for all Brazilian document validators in [@br-validators/core](https://www.npmjs.com/package/@br-validators/core).
4
4
 
5
+ **Repo:** [github.com/AlexandreZanata/br-validators](https://github.com/AlexandreZanata/br-validators)
6
+
5
7
  ---
6
8
 
7
9
  ## Install
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
2
 
4
3
  // src/program.ts
5
4
  import { Command } from "commander";
@@ -7,22 +6,103 @@ import { Command } from "commander";
7
6
  // src/handlers.ts
8
7
  import { readFileSync } from "fs";
9
8
 
10
- // src/commands/cep.ts
9
+ // src/commands/brcode.ts
11
10
  import {
12
- CEP_OFFICIAL_SOURCE_URL,
13
- formatCep,
14
- stripCep,
15
- validateCep
11
+ BRCODE_OFFICIAL_SOURCE_URL,
12
+ parseBrCode,
13
+ validateBrCode
16
14
  } from "@br-validators/core";
17
15
 
18
16
  // src/constants.ts
19
- var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"];
17
+ var SUPPORTED_TYPES = ["cnpj", "cpf", "cep", "telefone", "brcode", "placa", "pis-pasep", "pix", "boleto", "cartao", "ie"];
20
18
  var EXIT = {
21
19
  OK: 0,
22
20
  INVALID: 1,
23
21
  USAGE: 2
24
22
  };
25
23
 
24
+ // src/commands/brcode.ts
25
+ function resolveInput(value, fileContent) {
26
+ const input = value ?? fileContent?.trim();
27
+ if (!input) {
28
+ return null;
29
+ }
30
+ return input;
31
+ }
32
+ function printBrCodeResult(result, options, io = { stdout: [], stderr: [] }) {
33
+ if (options.json) {
34
+ io.stdout.push(
35
+ JSON.stringify(
36
+ result.ok ? {
37
+ ok: true,
38
+ value: result.value,
39
+ format: result.format,
40
+ merchantName: result.merchantName,
41
+ merchantCity: result.merchantCity,
42
+ ...result.amount ? { amount: result.amount } : {},
43
+ ...result.txid ? { txid: result.txid } : {},
44
+ ...result.pixKey ? { pixKey: result.pixKey, pixKeyType: result.pixKeyType } : {},
45
+ ...result.pixInitiationUrl ? { pixInitiationUrl: result.pixInitiationUrl } : {},
46
+ ...options.source ? { source: options.source } : {}
47
+ } : { ok: false, code: result.code, message: result.message },
48
+ null,
49
+ 2
50
+ )
51
+ );
52
+ return result.ok ? EXIT.OK : EXIT.INVALID;
53
+ }
54
+ if (options.quiet) {
55
+ return result.ok ? EXIT.OK : EXIT.INVALID;
56
+ }
57
+ if (result.ok) {
58
+ io.stdout.push("valid: yes");
59
+ io.stdout.push(`merchantName: ${result.merchantName}`);
60
+ io.stdout.push(`merchantCity: ${result.merchantCity}`);
61
+ if (result.amount) {
62
+ io.stdout.push(`amount: ${result.amount}`);
63
+ }
64
+ if (result.txid) {
65
+ io.stdout.push(`txid: ${result.txid}`);
66
+ }
67
+ if (result.pixKey) {
68
+ io.stdout.push(`pixKey: ${result.pixKey}`);
69
+ io.stdout.push(`pixKeyType: ${result.pixKeyType}`);
70
+ }
71
+ if (result.pixInitiationUrl) {
72
+ io.stdout.push(`pixInitiationUrl: ${result.pixInitiationUrl}`);
73
+ }
74
+ if (options.source) {
75
+ io.stdout.push(`source: ${options.source}`);
76
+ }
77
+ return EXIT.OK;
78
+ }
79
+ io.stderr.push("valid: no");
80
+ io.stderr.push(`code: ${result.code}`);
81
+ io.stderr.push(`message: ${result.message}`);
82
+ return EXIT.INVALID;
83
+ }
84
+ function runBrCodeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
85
+ const source = options.source ? BRCODE_OFFICIAL_SOURCE_URL : void 0;
86
+ const result = action === "validate" ? validateBrCode(input) : parseBrCode(input);
87
+ return printBrCodeResult(result, { json: options.json, quiet: options.quiet, source }, io);
88
+ }
89
+ function runBrCode(action, value, options, io = { stdout: [], stderr: [] }) {
90
+ const input = resolveInput(value, options.file);
91
+ if (input === null) {
92
+ io.stderr.push("Missing BR Code payload. Pass an argument or use --file.");
93
+ return EXIT.USAGE;
94
+ }
95
+ return runBrCodeCommand(action, input, options, io);
96
+ }
97
+
98
+ // src/commands/cep.ts
99
+ import {
100
+ CEP_OFFICIAL_SOURCE_URL,
101
+ formatCep,
102
+ stripCep,
103
+ validateCep
104
+ } from "@br-validators/core";
105
+
26
106
  // src/output.ts
27
107
  function printValidation(result, options, io = { stdout: [], stderr: [] }) {
28
108
  if (options.json) {
@@ -82,7 +162,7 @@ function printStrip(value, options, io = { stdout: [] }) {
82
162
  }
83
163
 
84
164
  // src/commands/cep.ts
85
- function resolveInput(value, fileContent) {
165
+ function resolveInput2(value, fileContent) {
86
166
  const input = value ?? fileContent?.trim();
87
167
  if (!input) {
88
168
  return null;
@@ -106,7 +186,7 @@ function runCepCommand(action, input, options, io = { stdout: [], stderr: [] })
106
186
  }
107
187
  }
108
188
  function runCep(action, value, options, io = { stdout: [], stderr: [] }) {
109
- const input = resolveInput(value, options.file);
189
+ const input = resolveInput2(value, options.file);
110
190
  if (input === null) {
111
191
  io.stderr.push("Missing CEP value. Pass an argument or use --file.");
112
192
  return EXIT.USAGE;
@@ -114,6 +194,79 @@ function runCep(action, value, options, io = { stdout: [], stderr: [] }) {
114
194
  return runCepCommand(action, input, options, io);
115
195
  }
116
196
 
197
+ // src/commands/telefone.ts
198
+ import {
199
+ TELEFONE_OFFICIAL_SOURCE_URL,
200
+ formatTelefone,
201
+ stripTelefone,
202
+ validateTelefone
203
+ } from "@br-validators/core";
204
+ function resolveInput3(value, fileContent) {
205
+ const input = value ?? fileContent?.trim();
206
+ if (!input) {
207
+ return null;
208
+ }
209
+ return input;
210
+ }
211
+ function printTelefoneValidation(result, options, io = { stdout: [], stderr: [] }) {
212
+ if (options.json) {
213
+ io.stdout.push(
214
+ JSON.stringify(
215
+ result.ok ? {
216
+ ok: true,
217
+ value: result.value,
218
+ tipo: result.tipo,
219
+ format: result.format,
220
+ ...options.source ? { source: options.source } : {}
221
+ } : { ok: false, code: result.code, message: result.message },
222
+ null,
223
+ 2
224
+ )
225
+ );
226
+ return result.ok ? EXIT.OK : EXIT.INVALID;
227
+ }
228
+ if (options.quiet) {
229
+ return result.ok ? EXIT.OK : EXIT.INVALID;
230
+ }
231
+ if (result.ok) {
232
+ io.stdout.push(`valid: yes (${result.tipo})`);
233
+ io.stdout.push(`value: ${result.value}`);
234
+ io.stdout.push(`format: ${result.format}`);
235
+ if (options.source) {
236
+ io.stdout.push(`source: ${options.source}`);
237
+ }
238
+ return EXIT.OK;
239
+ }
240
+ io.stderr.push("valid: no");
241
+ io.stderr.push(`code: ${result.code}`);
242
+ io.stderr.push(`message: ${result.message}`);
243
+ return EXIT.INVALID;
244
+ }
245
+ function runTelefoneCommand(action, input, options, io = { stdout: [], stderr: [] }) {
246
+ const source = options.source ? TELEFONE_OFFICIAL_SOURCE_URL : void 0;
247
+ switch (action) {
248
+ case "validate":
249
+ return printTelefoneValidation(validateTelefone(input), { json: options.json, quiet: options.quiet, source }, io);
250
+ case "format":
251
+ return printFormat(formatTelefone(input), { json: options.json, quiet: options.quiet }, io);
252
+ case "strip":
253
+ return printStrip(stripTelefone(input), { json: options.json }, io);
254
+ default: {
255
+ const _exhaustive = action;
256
+ io.stderr.push(`Unknown action: ${_exhaustive}`);
257
+ return EXIT.USAGE;
258
+ }
259
+ }
260
+ }
261
+ function runTelefone(action, value, options, io = { stdout: [], stderr: [] }) {
262
+ const input = resolveInput3(value, options.file);
263
+ if (input === null) {
264
+ io.stderr.push("Missing telephone value. Pass an argument or use --file.");
265
+ return EXIT.USAGE;
266
+ }
267
+ return runTelefoneCommand(action, input, options, io);
268
+ }
269
+
117
270
  // src/commands/cnpj.ts
118
271
  import {
119
272
  CNPJ_OFFICIAL_SOURCE_URL,
@@ -121,7 +274,7 @@ import {
121
274
  stripCnpj,
122
275
  validateCnpj
123
276
  } from "@br-validators/core";
124
- function resolveInput2(value, fileContent) {
277
+ function resolveInput4(value, fileContent) {
125
278
  const input = value ?? fileContent?.trim();
126
279
  if (!input) {
127
280
  return null;
@@ -145,7 +298,7 @@ function runCnpjCommand(action, input, options, io = { stdout: [], stderr: [] })
145
298
  }
146
299
  }
147
300
  function runCnpj(action, value, options, io = { stdout: [], stderr: [] }) {
148
- const input = resolveInput2(value, options.file);
301
+ const input = resolveInput4(value, options.file);
149
302
  if (input === null) {
150
303
  io.stderr.push("Missing CNPJ value. Pass an argument or use --file.");
151
304
  return EXIT.USAGE;
@@ -160,7 +313,7 @@ import {
160
313
  stripCpf,
161
314
  validateCpf
162
315
  } from "@br-validators/core";
163
- function resolveInput3(value, fileContent) {
316
+ function resolveInput5(value, fileContent) {
164
317
  const input = value ?? fileContent?.trim();
165
318
  if (!input) {
166
319
  return null;
@@ -184,7 +337,7 @@ function runCpfCommand(action, input, options, io = { stdout: [], stderr: [] })
184
337
  }
185
338
  }
186
339
  function runCpf(action, value, options, io = { stdout: [], stderr: [] }) {
187
- const input = resolveInput3(value, options.file);
340
+ const input = resolveInput5(value, options.file);
188
341
  if (input === null) {
189
342
  io.stderr.push("Missing CPF value. Pass an argument or use --file.");
190
343
  return EXIT.USAGE;
@@ -200,7 +353,7 @@ import {
200
353
  stripPlaca,
201
354
  validatePlaca
202
355
  } from "@br-validators/core";
203
- function resolveInput4(value, fileContent) {
356
+ function resolveInput6(value, fileContent) {
204
357
  const input = value ?? fileContent?.trim();
205
358
  if (!input) {
206
359
  return null;
@@ -226,7 +379,7 @@ function runPlacaCommand(action, input, options, io = { stdout: [], stderr: [] }
226
379
  }
227
380
  }
228
381
  function runPlaca(action, value, options, io = { stdout: [], stderr: [] }) {
229
- const input = resolveInput4(value, options.file);
382
+ const input = resolveInput6(value, options.file);
230
383
  if (input === null) {
231
384
  io.stderr.push("Missing placa value. Pass an argument or use --file.");
232
385
  return EXIT.USAGE;
@@ -241,7 +394,7 @@ import {
241
394
  stripPisPasep,
242
395
  validatePisPasep
243
396
  } from "@br-validators/core";
244
- function resolveInput5(value, fileContent) {
397
+ function resolveInput7(value, fileContent) {
245
398
  const input = value ?? fileContent?.trim();
246
399
  if (!input) {
247
400
  return null;
@@ -265,7 +418,7 @@ function runPisPasepCommand(action, input, options, io = { stdout: [], stderr: [
265
418
  }
266
419
  }
267
420
  function runPisPasep(action, value, options, io = { stdout: [], stderr: [] }) {
268
- const input = resolveInput5(value, options.file);
421
+ const input = resolveInput7(value, options.file);
269
422
  if (input === null) {
270
423
  io.stderr.push("Missing PIS/PASEP value. Pass an argument or use --file.");
271
424
  return EXIT.USAGE;
@@ -280,7 +433,7 @@ import {
280
433
  formatPixKey,
281
434
  validatePixKey
282
435
  } from "@br-validators/core";
283
- function resolveInput6(value, fileContent) {
436
+ function resolveInput8(value, fileContent) {
284
437
  const input = value ?? fileContent?.trim();
285
438
  if (!input) {
286
439
  return null;
@@ -355,7 +508,7 @@ function runPixCommand(action, input, options, io = { stdout: [], stderr: [] })
355
508
  }
356
509
  }
357
510
  function runPix(action, value, options, io = { stdout: [], stderr: [] }) {
358
- const input = resolveInput6(value, options.file);
511
+ const input = resolveInput8(value, options.file);
359
512
  if (input === null) {
360
513
  io.stderr.push("Missing PIX key value. Pass an argument or use --file.");
361
514
  return EXIT.USAGE;
@@ -374,7 +527,7 @@ import {
374
527
  stripLinhaDigitavel,
375
528
  validateBoleto
376
529
  } from "@br-validators/core";
377
- function resolveInput7(value, fileContent) {
530
+ function resolveInput9(value, fileContent) {
378
531
  const input = value ?? fileContent?.trim();
379
532
  if (!input) {
380
533
  return null;
@@ -498,7 +651,7 @@ function runBoletoCommand(action, input, options, direction, io = { stdout: [],
498
651
  }
499
652
  }
500
653
  function runBoleto(action, value, options, direction, io = { stdout: [], stderr: [] }) {
501
- const input = resolveInput7(value, options.file);
654
+ const input = resolveInput9(value, options.file);
502
655
  if (input === null) {
503
656
  io.stderr.push("Missing boleto value. Pass an argument or use --file.");
504
657
  return EXIT.USAGE;
@@ -514,7 +667,7 @@ import {
514
667
  stripCartaoCredito,
515
668
  validateCartaoCredito
516
669
  } from "@br-validators/core";
517
- function resolveInput8(value, fileContent) {
670
+ function resolveInput10(value, fileContent) {
518
671
  const input = value ?? fileContent?.trim();
519
672
  if (!input) {
520
673
  return null;
@@ -590,7 +743,7 @@ function runCartaoCommand(action, input, options, io = { stdout: [], stderr: []
590
743
  }
591
744
  }
592
745
  function runCartao(action, value, options, io = { stdout: [], stderr: [] }) {
593
- const input = resolveInput8(value, options.file);
746
+ const input = resolveInput10(value, options.file);
594
747
  if (input === null) {
595
748
  io.stderr.push("Missing credit card PAN value. Pass an argument or use --file.");
596
749
  return EXIT.USAGE;
@@ -606,7 +759,7 @@ import {
606
759
  stripInscricaoEstadual,
607
760
  validateInscricaoEstadual
608
761
  } from "@br-validators/core";
609
- function resolveInput9(value, fileContent) {
762
+ function resolveInput11(value, fileContent) {
610
763
  const input = value ?? fileContent?.trim();
611
764
  if (!input) {
612
765
  return null;
@@ -687,7 +840,7 @@ function runIeCommand(action, input, options, io = { stdout: [], stderr: [] }) {
687
840
  }
688
841
  }
689
842
  function runIe(action, value, options, io = { stdout: [], stderr: [] }) {
690
- const input = resolveInput9(value, options.file);
843
+ const input = resolveInput11(value, options.file);
691
844
  if (input === null) {
692
845
  io.stderr.push("Missing IE value. Pass an argument or use --file.");
693
846
  return EXIT.USAGE;
@@ -778,6 +931,27 @@ function handleCepCli(action, value, opts, io = { stdout: [], stderr: [] }) {
778
931
  io
779
932
  );
780
933
  }
934
+ function handleTelefoneCli(action, value, opts, io = { stdout: [], stderr: [] }) {
935
+ let fileContent;
936
+ if (opts.file) {
937
+ const content = readInputFile(opts.file, io);
938
+ if (content === null) {
939
+ return EXIT.USAGE;
940
+ }
941
+ fileContent = content;
942
+ }
943
+ return runTelefone(
944
+ action,
945
+ value,
946
+ {
947
+ json: Boolean(opts.json),
948
+ quiet: Boolean(opts.quiet),
949
+ source: Boolean(opts.source),
950
+ file: fileContent
951
+ },
952
+ io
953
+ );
954
+ }
781
955
  function handlePlacaCli(action, value, opts, io = { stdout: [], stderr: [] }) {
782
956
  let fileContent;
783
957
  if (opts.file) {
@@ -907,6 +1081,27 @@ function handleCartaoCreditoCli(action, value, opts, io = { stdout: [], stderr:
907
1081
  io
908
1082
  );
909
1083
  }
1084
+ function handleBrCodeCli(action, value, opts, io = { stdout: [], stderr: [] }) {
1085
+ let fileContent;
1086
+ if (opts.file) {
1087
+ const content = readInputFile(opts.file, io);
1088
+ if (content === null) {
1089
+ return EXIT.USAGE;
1090
+ }
1091
+ fileContent = content;
1092
+ }
1093
+ return runBrCode(
1094
+ action,
1095
+ value,
1096
+ {
1097
+ json: Boolean(opts.json),
1098
+ quiet: Boolean(opts.quiet),
1099
+ source: Boolean(opts.source),
1100
+ file: fileContent
1101
+ },
1102
+ io
1103
+ );
1104
+ }
910
1105
  function handleIeCli(action, value, opts, io = { stdout: [], stderr: [] }) {
911
1106
  let fileContent;
912
1107
  if (opts.file) {
@@ -967,6 +1162,22 @@ function createProgram() {
967
1162
  writeCliIo(io);
968
1163
  });
969
1164
  }
1165
+ const telefone = program.command("telefone").description("Telefone \u2014 Brazilian fixo/celular (Anatel DDD)");
1166
+ for (const action of ["validate", "format", "strip"]) {
1167
+ 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) => {
1168
+ const io = { stdout: [], stderr: [] };
1169
+ process.exitCode = handleTelefoneCli(action, value, opts, io);
1170
+ writeCliIo(io);
1171
+ });
1172
+ }
1173
+ const brcode = program.command("brcode").description("BR Code \u2014 PIX QR payload (Bacen EMV TLV)");
1174
+ for (const action of ["parse", "validate"]) {
1175
+ 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) => {
1176
+ const io = { stdout: [], stderr: [] };
1177
+ process.exitCode = handleBrCodeCli(action, value, opts, io);
1178
+ writeCliIo(io);
1179
+ });
1180
+ }
970
1181
  const placa = program.command("placa").description("Placa \u2014 legacy + Mercosul (CONTRAN)");
971
1182
  for (const action of ["validate", "format", "strip", "convert"]) {
972
1183
  placa.command(action).description(`${action} a license plate`).argument("[value]", "Placa 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) => {
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@br-validators/cli",
3
- "version": "0.10.0-alpha.0",
3
+ "version": "0.11.0-alpha.0",
4
4
  "description": "Terminal CLI for Brazilian document validation — CPF, CNPJ, CEP, IE, PIX, boleto, and more",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/AlexandreZanata/doc-raiz.git",
9
+ "url": "git+https://github.com/AlexandreZanata/br-validators.git",
10
10
  "directory": "apps/cli"
11
11
  },
12
- "homepage": "https://github.com/AlexandreZanata/doc-raiz#readme",
12
+ "homepage": "https://github.com/AlexandreZanata/br-validators/tree/main/apps/cli#readme",
13
13
  "bugs": {
14
- "url": "https://github.com/AlexandreZanata/doc-raiz/issues"
14
+ "url": "https://github.com/AlexandreZanata/br-validators/issues"
15
15
  },
16
16
  "keywords": [
17
17
  "brazil",
@@ -21,14 +21,15 @@
21
21
  "cnpj"
22
22
  ],
23
23
  "publishConfig": {
24
- "access": "public"
24
+ "access": "public",
25
+ "tag": "alpha"
25
26
  },
26
27
  "bin": {
27
- "br-validators": "./dist/index.js"
28
+ "br-validators": "dist/index.js"
28
29
  },
29
30
  "dependencies": {
30
31
  "commander": "^13.1.0",
31
- "@br-validators/core": "0.10.0-alpha.0"
32
+ "@br-validators/core": "0.11.0-alpha.0"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@types/node": "^22.15.21",
@@ -43,6 +44,8 @@
43
44
  ],
44
45
  "scripts": {
45
46
  "build": "tsup",
47
+ "pretest": "pnpm run build",
48
+ "pretest:coverage": "pnpm run build",
46
49
  "pretypecheck": "pnpm --filter @br-validators/core build",
47
50
  "test": "vitest run",
48
51
  "test:coverage": "vitest run --coverage",